001/* 002 * Copyright 2011-2018 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2011-2018 Ping Identity Corporation 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU General Public License (GPLv2 only) 010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 011 * as published by the Free Software Foundation. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Public License for more details. 017 * 018 * You should have received a copy of the GNU General Public License 019 * along with this program; if not, see <http://www.gnu.org/licenses>. 020 */ 021package com.unboundid.ldap.sdk; 022 023 024 025import java.nio.charset.StandardCharsets; 026import java.util.ArrayList; 027import java.util.List; 028 029import com.unboundid.asn1.ASN1OctetString; 030import com.unboundid.util.NotMutable; 031import com.unboundid.util.ThreadSafety; 032import com.unboundid.util.ThreadSafetyLevel; 033import com.unboundid.util.Validator; 034 035 036 037/** 038 * This class provides a mechanism for performing SASL authentication in a 039 * generic manner. The caller is responsible for properly encoding the 040 * credentials (if any) and interpreting the result. Further, if the requested 041 * SASL mechanism is one that requires multiple stages, then the caller is 042 * responsible for all processing in each stage. 043 */ 044@NotMutable() 045@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 046public final class GenericSASLBindRequest 047 extends SASLBindRequest 048{ 049 /** 050 * The serial version UID for this serializable class. 051 */ 052 private static final long serialVersionUID = 7740968332104559230L; 053 054 055 056 // The SASL credentials that should be used for the bind request. 057 private final ASN1OctetString credentials; 058 059 // The bind DN to use for the bind request. 060 private final String bindDN; 061 062 // The name of the SASL mechanism that should be used for the bind request. 063 private final String mechanism; 064 065 066 067 /** 068 * Creates a new generic SASL bind request with the provided information. 069 * 070 * @param bindDN The bind DN that should be used for the request. It 071 * may be {@code null} if the target identity should be 072 * derived from the credentials or some other source. 073 * @param mechanism The name of the mechanism that should be used for the 074 * SASL bind. It must not be {@code null}. 075 * @param credentials The credentials that should be used for the SASL bind. 076 * It may be {@code null} if no credentials should be 077 * used. 078 * @param controls The set of controls to include in the SASL bind 079 * request. It may be {@code null} or empty if no 080 * request controls are needed. 081 */ 082 public GenericSASLBindRequest(final String bindDN, final String mechanism, 083 final ASN1OctetString credentials, 084 final Control... controls) 085 { 086 super(controls); 087 088 Validator.ensureNotNull(mechanism); 089 090 this.bindDN = bindDN; 091 this.mechanism = mechanism; 092 this.credentials = credentials; 093 } 094 095 096 097 /** 098 * Retrieves the bind DN for this SASL bind request, if any. 099 * 100 * @return The bind DN for this SASL bind request, or {@code null} if the 101 * target identity should be determined from the credentials or some 102 * other mechanism. 103 */ 104 public String getBindDN() 105 { 106 return bindDN; 107 } 108 109 110 111 /** 112 * {@inheritDoc} 113 */ 114 @Override() 115 public String getSASLMechanismName() 116 { 117 return mechanism; 118 } 119 120 121 122 /** 123 * Retrieves the credentials for the SASL bind request, if any. 124 * 125 * @return The credentials for the SASL bind request, or {@code null} if 126 * there are none. 127 */ 128 public ASN1OctetString getCredentials() 129 { 130 return credentials; 131 } 132 133 134 135 /** 136 * {@inheritDoc} 137 */ 138 @Override() 139 protected BindResult process(final LDAPConnection connection, final int depth) 140 throws LDAPException 141 { 142 return sendBindRequest(connection, bindDN, credentials, getControls(), 143 getResponseTimeoutMillis(connection)); 144 } 145 146 147 148 /** 149 * {@inheritDoc} 150 */ 151 @Override() 152 public GenericSASLBindRequest duplicate() 153 { 154 return duplicate(getControls()); 155 } 156 157 158 159 /** 160 * {@inheritDoc} 161 */ 162 @Override() 163 public GenericSASLBindRequest duplicate(final Control[] controls) 164 { 165 return new GenericSASLBindRequest(bindDN, mechanism, credentials, 166 controls); 167 } 168 169 170 171 /** 172 * {@inheritDoc} 173 */ 174 @Override() 175 public void toString(final StringBuilder buffer) 176 { 177 buffer.append("GenericSASLBindRequest(mechanism='"); 178 buffer.append(mechanism); 179 buffer.append('\''); 180 181 if (bindDN != null) 182 { 183 buffer.append(", bindDN='"); 184 buffer.append(bindDN); 185 buffer.append('\''); 186 } 187 188 if (credentials != null) 189 { 190 buffer.append(", credentials=byte["); 191 buffer.append(credentials.getValueLength()); 192 buffer.append(']'); 193 } 194 195 final Control[] controls = getControls(); 196 if (controls.length > 0) 197 { 198 buffer.append(", controls={"); 199 for (int i=0; i < controls.length; i++) 200 { 201 if (i > 0) 202 { 203 buffer.append(", "); 204 } 205 206 buffer.append(controls[i]); 207 } 208 buffer.append('}'); 209 } 210 211 buffer.append(')'); 212 } 213 214 215 216 /** 217 * {@inheritDoc} 218 */ 219 @Override() 220 public void toCode(final List<String> lineList, final String requestID, 221 final int indentSpaces, final boolean includeProcessing) 222 { 223 // Create the request variable. 224 final ArrayList<ToCodeArgHelper> constructorArgs = new ArrayList<>(4); 225 constructorArgs.add(ToCodeArgHelper.createString(bindDN, "Bind DN")); 226 constructorArgs.add(ToCodeArgHelper.createString(mechanism, 227 "SASL Mechanism Name")); 228 constructorArgs.add(ToCodeArgHelper.createByteArray( 229 "---redacted-SASL-credentials".getBytes(StandardCharsets.UTF_8), true, 230 "SASL Credentials")); 231 232 final Control[] controls = getControls(); 233 if (controls.length > 0) 234 { 235 constructorArgs.add(ToCodeArgHelper.createControlArray(controls, 236 "Bind Controls")); 237 } 238 239 ToCodeHelper.generateMethodCall(lineList, indentSpaces, 240 "GenericSASLBindRequest", requestID + "Request", 241 "new GenericSASLBindRequest", constructorArgs); 242 243 244 // Add lines for processing the request and obtaining the result. 245 if (includeProcessing) 246 { 247 // Generate a string with the appropriate indent. 248 final StringBuilder buffer = new StringBuilder(); 249 for (int i=0; i < indentSpaces; i++) 250 { 251 buffer.append(' '); 252 } 253 final String indent = buffer.toString(); 254 255 lineList.add(""); 256 lineList.add(indent + '{'); 257 lineList.add(indent + " BindResult " + requestID + 258 "Result = connection.bind(" + requestID + "Request);"); 259 lineList.add(indent + " // The bind was processed successfully."); 260 lineList.add(indent + '}'); 261 lineList.add(indent + "catch (SASLBindInProgressException e)"); 262 lineList.add(indent + '{'); 263 lineList.add(indent + " // The SASL bind requires multiple stages. " + 264 "Continue it here."); 265 lineList.add(indent + " // Do not attempt to use the connection for " + 266 "any other purpose until bind processing has completed."); 267 lineList.add(indent + '}'); 268 lineList.add(indent + "catch (LDAPException e)"); 269 lineList.add(indent + '{'); 270 lineList.add(indent + " // The bind failed. Maybe the following will " + 271 "help explain why."); 272 lineList.add(indent + " // Note that the connection is now likely in " + 273 "an unauthenticated state."); 274 lineList.add(indent + " ResultCode resultCode = e.getResultCode();"); 275 lineList.add(indent + " String message = e.getMessage();"); 276 lineList.add(indent + " String matchedDN = e.getMatchedDN();"); 277 lineList.add(indent + " String[] referralURLs = e.getReferralURLs();"); 278 lineList.add(indent + " Control[] responseControls = " + 279 "e.getResponseControls();"); 280 lineList.add(indent + '}'); 281 } 282 } 283}