Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2019-2023 Ping Identity Corporation
* All Rights Reserved.
*/
/*
* Copyright 2019-2023 Ping Identity Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Copyright (C) 2019-2023 Ping Identity Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPLv2 only)
* or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see .
*/
package com.unboundid.ldap.sdk;
import java.security.MessageDigest;
import java.util.List;
import java.util.logging.Level;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import com.unboundid.asn1.ASN1OctetString;
import com.unboundid.util.CryptoHelper;
import com.unboundid.util.Debug;
import com.unboundid.util.DebugType;
import com.unboundid.util.Extensible;
import com.unboundid.util.NotNull;
import com.unboundid.util.Nullable;
import com.unboundid.util.ThreadSafety;
import com.unboundid.util.ThreadSafetyLevel;
import com.unboundid.util.Validator;
import static com.unboundid.ldap.sdk.LDAPMessages.*;
/**
* This class provides the basis for bind requests that use the salted
* challenge-response authentication mechanism (SCRAM) described in
* RFC 5802 and updated in
* RFC 7677. Subclasses
* should extend this class to provide support for specific algorithms.
*
* Note that this implementation does not support the PLUS variants of these
* algorithms, which requires channel binding support.
*/
@Extensible()
@ThreadSafety(level= ThreadSafetyLevel.INTERFACE_NOT_THREADSAFE)
public abstract class SCRAMBindRequest
extends SASLBindRequest
{
/**
* The serial version UID for this serializable class.
*/
private static final long serialVersionUID = -1141722265190138366L;
// The password for this bind request.
@NotNull private final ASN1OctetString password;
// The username for this bind request.
@NotNull private final String username;
/**
* Creates a new SCRAM bind request with the provided information.
*
* @param username The username for this bind request. It must not be
* {@code null} or empty.
* @param password The password for this bind request. It must not be
* {@code null} or empty.
* @param controls The set of controls to include in the bind request. It
* may be {@code null} or empty if no controls are needed.
*/
public SCRAMBindRequest(@NotNull final String username,
@NotNull final ASN1OctetString password,
@Nullable final Control... controls)
{
super(controls);
Validator.ensureNotNullOrEmpty(username,
"SCRAMBindRequest.username must not be null or empty");
Validator.ensureTrue(
((password != null) && (password.getValueLength() > 0)),
"SCRAMBindRequest.password must not be null or empty");
this.username = username;
this.password = password;
}
/**
* Retrieves the username for this bind request.
*
* @return The password for this bind request.
*/
@NotNull()
public final String getUsername()
{
return username;
}
/**
* Retrieves the password for this bind request, as a string.
*
* @return The password for this bind request, as a string.
*/
@NotNull()
public final String getPasswordString()
{
return password.stringValue();
}
/**
* Retrieves the bytes that comprise the password for this bind request.
*
* @return The bytes that comprise the password for this bind request.
*/
@NotNull()
public final byte[] getPasswordBytes()
{
return password.getValue();
}
/**
* Retrieves the name of the digest algorithm that will be used in the
* authentication processing.
*
* @return The name of the digest algorithm that will be used in the
* authentication processing.
*/
@NotNull()
protected abstract String getDigestAlgorithmName();
/**
* Retrieves the name of the MAC algorithm that will be used in the
* authentication processing.
*
* @return The name of the MAC algorithm that will be used in the
* authentication processing.
*/
@NotNull()
protected abstract String getMACAlgorithmName();
/**
* {@inheritDoc}
*/
@Override()
@NotNull()
protected final BindResult process(@NotNull final LDAPConnection connection,
final int depth)
throws LDAPException
{
setReferralDepth(depth);
// Generate the client first message and send it to the server.
final SCRAMClientFirstMessage clientFirstMessage =
new SCRAMClientFirstMessage(this);
if (Debug.debugEnabled())
{
Debug.debug(Level.INFO, DebugType.LDAP,
"Sending " + getSASLMechanismName() + " client first message " +
clientFirstMessage);
}
final BindResult serverFirstResult = sendBindRequest(connection, null,
new ASN1OctetString(clientFirstMessage.getClientFirstMessage()),
getControls(), getResponseTimeoutMillis(connection));
// If the result code from the server first result is anything other than
// SASL_BIND_IN_PROGRESS, then return that result as a failure.
if (serverFirstResult.getResultCode() != ResultCode.SASL_BIND_IN_PROGRESS)
{
return serverFirstResult;
}
// Parse the server first result, and use it to compute the client final
// message.
final SCRAMServerFirstMessage serverFirstMessage =
new SCRAMServerFirstMessage(this, clientFirstMessage,
serverFirstResult);
if (Debug.debugEnabled())
{
Debug.debug(Level.INFO, DebugType.LDAP,
"Received " + getSASLMechanismName() + " server first message " +
serverFirstMessage);
}
final SCRAMClientFinalMessage clientFinalMessage =
new SCRAMClientFinalMessage(this, clientFirstMessage,
serverFirstMessage);
if (Debug.debugEnabled())
{
Debug.debug(Level.INFO, DebugType.LDAP,
"Sending " + getSASLMechanismName() + " client final message " +
clientFinalMessage);
}
// Send the server final bind request to the server and get the result.
// We don't care what the result code was, because the server final message
// processing will handle both success and failure.
final BindResult serverFinalResult = sendBindRequest(connection, null,
new ASN1OctetString(clientFinalMessage.getClientFinalMessage()),
getControls(), getResponseTimeoutMillis(connection));
final SCRAMServerFinalMessage serverFinalMessage =
new SCRAMServerFinalMessage(this, clientFirstMessage,
clientFinalMessage, serverFinalResult);
if (Debug.debugEnabled())
{
Debug.debug(Level.INFO, DebugType.LDAP,
"Received " + getSASLMechanismName() + " server final message " +
serverFinalMessage);
}
// If we've gotten here, then the bind was successful. Return the server
// final result.
return serverFinalResult;
}
/**
* Computes a MAC of the provided data with the given key.
*
* @param key The bytes to use as the key for the MAC.
* @param data The data for which to generate the MAC.
*
* @return The MAC that was computed.
*
* @throws LDAPBindException If a problem is encountered while computing the
* MAC.
*/
@NotNull()
final byte[] mac(@NotNull final byte[] key, @NotNull final byte[] data)
throws LDAPBindException
{
return getMac(key).doFinal(data);
}
/**
* Retrieves a MAC generator for the provided key.
*
* @param key The bytes to use as the key for the MAC.
*
* @return The MAC generator.
*
* @throws LDAPBindException If a problem is encountered while obtaining the
* MAC generator.
*/
@NotNull()
final Mac getMac(@NotNull final byte[] key)
throws LDAPBindException
{
try
{
final Mac mac = CryptoHelper.getMAC(getMACAlgorithmName());
final SecretKeySpec macKey =
new SecretKeySpec(key, getMACAlgorithmName());
mac.init(macKey);
return mac;
}
catch (final Exception e)
{
Debug.debugException(e);
throw new LDAPBindException(new BindResult(-1,
ResultCode.LOCAL_ERROR,
ERR_SCRAM_BIND_REQUEST_CANNOT_GET_MAC.get(getSASLMechanismName(),
getMACAlgorithmName()),
null, null, null, null));
}
}
/**
* Computes a message digest of the provided data with the given key.
*
* @param data The data for which to generate the digest.
*
* @return The digest that was computed.
*
* @throws LDAPBindException If a problem is encountered while computing the
* digest.
*/
@NotNull()
final byte[] digest(@NotNull final byte[] data)
throws LDAPBindException
{
try
{
final MessageDigest digest =
CryptoHelper.getMessageDigest(getDigestAlgorithmName());
return digest.digest(data);
}
catch (final Exception e)
{
Debug.debugException(e);
throw new LDAPBindException(new BindResult(-1,
ResultCode.LOCAL_ERROR,
ERR_SCRAM_BIND_REQUEST_CANNOT_GET_DIGEST.get(
getSASLMechanismName(), getDigestAlgorithmName()),
null, null, null, null));
}
}
/**
* {@inheritDoc}
*/
@Override()
@NotNull()
public abstract SCRAMBindRequest getRebindRequest(
@NotNull final String host,
final int port);
/**
* {@inheritDoc}
*/
@Override()
@NotNull()
public abstract SCRAMBindRequest duplicate();
/**
* {@inheritDoc}
*/
@Override()
@NotNull()
public abstract SCRAMBindRequest duplicate(@NotNull final Control[] controls);
/**
* {@inheritDoc}
*/
@Override()
public abstract void toString(@NotNull final StringBuilder buffer);
/**
* {@inheritDoc}
*/
@Override()
public abstract void toCode(@NotNull final List lineList,
@NotNull final String requestID,
final int indentSpaces,
final boolean includeProcessing);
}