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