001/* 002 * Copyright 2019-2024 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2019-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) 2019-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.util.ArrayList; 041import java.util.List; 042 043import com.unboundid.asn1.ASN1OctetString; 044import com.unboundid.util.NotNull; 045import com.unboundid.util.Nullable; 046import com.unboundid.util.ThreadSafety; 047import com.unboundid.util.ThreadSafetyLevel; 048 049 050 051/** 052 * This class provides an implementation of the SCRAM-SHA-256 SASL mechanism as 053 * described in <A HREF="http://www.ietf.org/rfc/rfc7677.txt">RFC 7677</A>. 054 */ 055@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE) 056public final class SCRAMSHA256BindRequest 057 extends SCRAMBindRequest 058{ 059 /** 060 * The name for the SCRAM-SHA-256 SASL mechanism. 061 */ 062 @NotNull public static final String SCRAM_SHA_256_MECHANISM_NAME = 063 "SCRAM-SHA-256"; 064 065 066 067 /** 068 * The serial version UID for this serializable class. 069 */ 070 private static final long serialVersionUID = -4396660110665214258L; 071 072 073 074 /** 075 * Creates a new SCRAM-SHA-256 bind request with the provided information. 076 * 077 * @param username The username for this bind request. It must not be {@code 078 * null} or empty. 079 * @param password The password for this bind request. It must not be {@code 080 * null} or empty. 081 * @param controls The set of controls to include in the bind request. It may 082 * be {@code null} or empty if no controls are needed. 083 */ 084 public SCRAMSHA256BindRequest(@NotNull final String username, 085 @NotNull final String password, 086 @Nullable final Control... controls) 087 { 088 super(username, new ASN1OctetString(password), controls); 089 } 090 091 092 093 /** 094 * Creates a new SCRAM-SHA-256 bind request with the provided information. 095 * 096 * @param username The username for this bind request. It must not be {@code 097 * null} or empty. 098 * @param password The password for this bind request. It must not be {@code 099 * null} or empty. 100 * @param controls The set of controls to include in the bind request. It may 101 * be {@code null} or empty if no controls are needed. 102 */ 103 public SCRAMSHA256BindRequest(@NotNull final String username, 104 @NotNull final byte[] password, 105 @Nullable final Control... controls) 106 { 107 super(username, new ASN1OctetString(password), controls); 108 } 109 110 111 112 /** 113 * {@inheritDoc} 114 */ 115 @Override() 116 @NotNull() 117 public String getSASLMechanismName() 118 { 119 return SCRAM_SHA_256_MECHANISM_NAME; 120 } 121 122 123 124 /** 125 * {@inheritDoc} 126 */ 127 @Override() 128 @NotNull() 129 protected String getDigestAlgorithmName() 130 { 131 return "SHA-256"; 132 } 133 134 135 136 /** 137 * {@inheritDoc} 138 */ 139 @Override() 140 @NotNull() 141 protected String getMACAlgorithmName() 142 { 143 return "HmacSHA256"; 144 } 145 146 147 148 /** 149 * {@inheritDoc} 150 */ 151 @Override() 152 @NotNull() 153 public SCRAMSHA256BindRequest getRebindRequest(@NotNull final String host, 154 final int port) 155 { 156 return duplicate(); 157 } 158 159 160 161 /** 162 * {@inheritDoc} 163 */ 164 @Override() 165 @NotNull() 166 public SCRAMSHA256BindRequest duplicate() 167 { 168 return duplicate(getControls()); 169 } 170 171 172 173 /** 174 * {@inheritDoc} 175 */ 176 @Override() 177 @NotNull() 178 public SCRAMSHA256BindRequest duplicate(@Nullable final Control[] controls) 179 { 180 final SCRAMSHA256BindRequest bindRequest = new SCRAMSHA256BindRequest( 181 getUsername(), getPasswordBytes(), controls); 182 bindRequest.setResponseTimeoutMillis(getResponseTimeoutMillis(null)); 183 bindRequest.setIntermediateResponseListener( 184 getIntermediateResponseListener()); 185 bindRequest.setReferralDepth(getReferralDepth()); 186 bindRequest.setReferralConnector(getReferralConnectorInternal()); 187 return bindRequest; 188 } 189 190 191 192 /** 193 * {@inheritDoc} 194 */ 195 @Override() 196 public void toString(@NotNull final StringBuilder buffer) 197 { 198 buffer.append("SCRAMSHA256BindRequest(username='"); 199 buffer.append(getUsername()); 200 buffer.append('\''); 201 202 final Control[] controls = getControls(); 203 if (controls.length > 0) 204 { 205 buffer.append(", controls={"); 206 for (int i=0; i < controls.length; i++) 207 { 208 if (i > 0) 209 { 210 buffer.append(", "); 211 } 212 213 buffer.append(controls[i]); 214 } 215 buffer.append('}'); 216 } 217 218 buffer.append(')'); 219 } 220 221 222 223 /** 224 * {@inheritDoc} 225 */ 226 @Override() 227 public void toCode(@NotNull final List<String> lineList, 228 @NotNull final String requestID, 229 final int indentSpaces, final boolean includeProcessing) 230 { 231 // Create the request variable. 232 final List<ToCodeArgHelper> constructorArgs = new ArrayList<>(4); 233 constructorArgs.add(ToCodeArgHelper.createString(getUsername(), 234 "Username")); 235 constructorArgs.add(ToCodeArgHelper.createString("---redacted-password---", 236 "Password")); 237 238 final Control[] controls = getControls(); 239 if (controls.length > 0) 240 { 241 constructorArgs.add(ToCodeArgHelper.createControlArray(controls, 242 "Bind Controls")); 243 } 244 245 ToCodeHelper.generateMethodCall(lineList, indentSpaces, 246 "SCRAMSHA256BindRequest", requestID + "Request", 247 "new SCRAMSHA256BindRequest", constructorArgs); 248 249 250 // Add lines for processing the request and obtaining the result. 251 if (includeProcessing) 252 { 253 // Generate a string with the appropriate indent. 254 final StringBuilder buffer = new StringBuilder(); 255 for (int i=0; i < indentSpaces; i++) 256 { 257 buffer.append(' '); 258 } 259 final String indent = buffer.toString(); 260 261 lineList.add(""); 262 lineList.add(indent + "try"); 263 lineList.add(indent + '{'); 264 lineList.add(indent + " BindResult " + requestID + 265 "Result = connection.bind(" + requestID + "Request);"); 266 lineList.add(indent + " // The bind was processed successfully."); 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}