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 2015-2017 UnboundID Corp.
* All Rights Reserved.
*/
/*
* Copyright (C) 2015-2017 UnboundID Corp.
*
* 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.util.json;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import com.unboundid.ldap.sdk.BindRequest;
import com.unboundid.ldap.sdk.CRAMMD5BindRequest;
import com.unboundid.ldap.sdk.DIGESTMD5BindRequest;
import com.unboundid.ldap.sdk.DIGESTMD5BindRequestProperties;
import com.unboundid.ldap.sdk.EXTERNALBindRequest;
import com.unboundid.ldap.sdk.GSSAPIBindRequest;
import com.unboundid.ldap.sdk.GSSAPIBindRequestProperties;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.PLAINBindRequest;
import com.unboundid.ldap.sdk.ResultCode;
import com.unboundid.ldap.sdk.SASLQualityOfProtection;
import com.unboundid.ldap.sdk.SimpleBindRequest;
import com.unboundid.util.NotMutable;
import com.unboundid.util.StaticUtils;
import com.unboundid.util.ThreadSafety;
import com.unboundid.util.ThreadSafetyLevel;
import static com.unboundid.util.json.JSONMessages.*;
/**
* This class provides a data structure and set of logic for interacting with
* the authentication details portion of a JSON object provided to the
* {@link LDAPConnectionDetailsJSONSpecification}.
*/
@NotMutable()
@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
final class AuthenticationDetails
implements Serializable
{
/**
* The name of the field that may be used to specify the authentication ID.
* This may be used in conjunction with the CRAM-MD5, DIGEST-MD5, GSSAPI, and
* PLAIN authentication types. It is required for use with those
* authentication types, and its value must be a string that represents an
* appropriate authentication ID for that authentication type.
*/
private static final String FIELD_AUTHENTICATION_ID = "authentication-id";
/**
* The name of the field that may be used to specify the type of
* authentication to perform. It is a required field, and its value must be a
* string with one of the following values: "none" (to indicate that no
* authentication should be performed), "simple" (to indicate LDAP simple
* authentication), "CRAM-MD5" (for the CRAM-MD5 SASL mechanism), "DIGEST-MD5"
* (for the DIGEST-MD5 SASL mechanism), "EXTERNAL" (for the EXTERNAL SASL
* mechanism), "GSSAPI" (for the GSSAPI SASL mechanism), or "PLAIN" (for the
* PLAIN SASL mechanism).
*/
private static final String FIELD_AUTHENTICATION_TYPE = "authentication-type";
/**
* The name of the field that may be used to specify the authorization ID.
* This may be used in conjunction with the DIGEST-MD5, EXTERNAL, GSSAPI, and
* PLAIN authentication types, and is an optional field for those
* authentication types. If present, its value must be a string that
* represents an appropriate authorization ID for that authentication type.
*/
private static final String FIELD_AUTHORIZATION_ID = "authorization-id";
/**
* The name of the field that may be used to specify the path to a JAAS
* configuration file. This is an optional field that may be used in
* conjunction with the GSSAPI authentication type. If present, its value
* must be a path to a valid JAAS configuration file. If it is not present,
* then a temporary configuration file will be automatically created and used
* for this purpose.
*/
private static final String FIELD_CONFIG_FILE_PATH = "config-file-path";
/**
* The name of the field that may be used to specify the bind DN. This field
* may be used in conjunction with the simple authentication type, and it is
* required for use in conjunction with that authentication type. Its value
* must be the DN to use when performing simple authentication, or an empty
* string to indicate anonymous authentication.
*/
private static final String FIELD_DN = "dn";
/**
* The name of the field that may be used to specify the address of the
* Kerberos KDC. This field may be used in conjunction with the GSSAPI
* authentication type, and it is an optional field for that authentication
* type. If present, its value must be a string that represents a resolvable
* name or IP address. If absent, the LDAP SDK will attempt to automatically
* determine the address of the Kerberos KDC from the underlying system.
*/
private static final String FIELD_KDC_ADDRESS = "kdc-address";
/**
* The name of the field that may be used to specify the password. This field
* may be used in conjunction with the simple, CRAM-MD5, DIGEST-MD5, GSSAPI,
* and PLAIN authentication types. It may not be used in conjunction with the
* password-file field. A password must be provided via either the password
* or password-file field for the simple CRAM-MD5, DIGEST-MD5, and PLAIN
* authentication types, and should be provided for the GSSAPI authentication
* type unless require-cached-credentials is true. If present, its value
* should be a string containing the password to use, or an empty string to
* indicate anonymous authentication.
*/
private static final String FIELD_PASSWORD = "password";
/**
* The name of the field that may be used to specify the path to a file
* containing the password. This field may be used in conjunction with the
* simple, CRAM-MD5, DIGEST-MD5, GSSAPI, and PLAIN authentication types. It
* may not be used in conjunction with the password field. A password must be
* provided via either the password or password-file field for the simple
* CRAM-MD5, DIGEST-MD5, and PLAIN authentication types, and should be
* provided for the GSSAPI authentication type unless
* require-cached-credentials is true. If present, its value should be a
* string containing the path to a file containing the password to use. The
* file should not be empty, so this field is not appropriate for anonymous
* authentication.
*/
private static final String FIELD_PASSWORD_FILE = "password-file";
/**
* The name of the field that may be used to specify the allowed quality of
* protection types. This may be used in conjunction with the DIGEST-MD5 and
* GSSAPI authentication types, and its value must be an array containing one
* or more of the following strings: "auth", "auth-int", and "auth-conf".
* If this is not provided, then a single-element array containing only the
* "auth" value will be used.
*/
private static final String FIELD_QOP = "qop";
/**
* The name of the field that may be used to specify the realm. This field
* may be used in conjunction with the DIGEST-MD5 and GSSAPI authentication
* types, and it is optional for those types. If present, its value must
* be a string that indicates the realm to use for the authentication. If
* it is absent, no realm will be provided to the server during the
* authentication process.
*/
private static final String FIELD_REALM = "realm";
/**
* The name of the field that may be used to indicate whether to attempt to
* automatically renew the Kerberos ticket-granting ticket. This field may be
* used in conjunction with the GSSAPI authentication type, and it is optional
* for use with that authentication type. If present, its value must be a
* boolean. If this field is absent, then a default value of {@code false}
* will be used.
*/
private static final String FIELD_RENEW_TGT = "renew-tgt";
/**
* The name of the field that may be used to indicate whether to require the
* use of cached credentials for authentication. This field may be used in
* conjunction with the GSSAPI authentication type, and it is optional for use
* with that authentication type. If present, its value must be a boolean.
* If this field is absent, then a default value of {@code false} will be
* used.
*/
private static final String FIELD_REQUIRE_CACHED_CREDENTIALS =
"require-cached-credentials";
/**
* The name of the field that may be used to specify the path to the Kerberos
* ticket cache to use if appropriate. This field may be used in conjunction
* with the GSSAPI authentication type, and it is optional for use with that
* authentication type. If present, its value must be the path to the
* Kerberos ticket cache. if this field is absent, then JVM will attempt to
* automatically determine the ticket cache path.
*/
private static final String FIELD_TICKET_CACHE_PATH = "ticket-cache-path";
/**
* The name of the field that may be used to indicate whether the client will
* be required to use credentials within the current subject. This field may
* be used in conjunction with the GSSAPI authentication type, and it is
* optional for use with that authentication type. If present, its value must
* be a boolean. If it is not provided, then a default value of {@code true}
* will be used.
*/
private static final String FIELD_USE_SUBJECT_CREDS_ONLY =
"use-subject-credentials-only";
/**
* The name of the field that may be used to indicate whether to use the
* Kerberos ticket cache. This field may be used in conjunction with the
* GSSAPI authentication type, and it is optional for use with that
* authentication type. If present, its value must be a boolean. If it is
* not provided, then a default value of {@code true} will be used.
*/
private static final String FIELD_USE_TICKET_CACHE = "use-ticket-cache";
/**
* The serial version UID for this serializable class.
*/
private static final long serialVersionUID = 2798778432389082274L;
// The bind request created from the specification.
private final BindRequest bindRequest;
/**
* Creates a new set of authentication details from the information contained
* in the provided JSON object.
*
* @param connectionDetailsObject The JSON object containing the LDAP
* connection details specification.
*
* @throws LDAPException If there is a problem with the authentication
* details data in the provided JSON object.
*/
AuthenticationDetails(final JSONObject connectionDetailsObject)
throws LDAPException
{
final JSONObject o = LDAPConnectionDetailsJSONSpecification.getObject(
connectionDetailsObject,
LDAPConnectionDetailsJSONSpecification.FIELD_AUTHENTICATION_DETAILS);
if (o == null)
{
bindRequest = null;
return;
}
final String authType =
LDAPConnectionDetailsJSONSpecification.getString(o,
FIELD_AUTHENTICATION_TYPE, null);
final String loweAuthType = StaticUtils.toLowerCase(authType);
if (loweAuthType == null)
{
throw new LDAPException(ResultCode.PARAM_ERROR,
ERR_AUTH_DETAILS_MISSING_REQUIRED_FIELD.get(
LDAPConnectionDetailsJSONSpecification.
FIELD_AUTHENTICATION_DETAILS,
FIELD_AUTHENTICATION_TYPE));
}
else if (loweAuthType.equals("none"))
{
LDAPConnectionDetailsJSONSpecification.validateAllowedFields(o,
LDAPConnectionDetailsJSONSpecification.FIELD_AUTHENTICATION_DETAILS,
FIELD_AUTHENTICATION_TYPE);
bindRequest = null;
}
else if (loweAuthType.equals("simple"))
{
validateAllowedFields(o, authType,
FIELD_DN,
FIELD_PASSWORD,
FIELD_PASSWORD_FILE);
final String dn = LDAPConnectionDetailsJSONSpecification.getString(o,
FIELD_DN, null);
if (dn == null)
{
throw new LDAPException(ResultCode.PARAM_ERROR,
ERR_AUTH_DETAILS_MISSING_REQUIRED_FIELD_FOR_AUTH_TYPE.get(
FIELD_DN, authType));
}
final String password = getPassword(o, authType, false);
bindRequest = new SimpleBindRequest(dn, password);
}
else if (loweAuthType.equals("cram-md5") ||
loweAuthType.equals("crammd5"))
{
validateAllowedFields(o, authType,
FIELD_AUTHENTICATION_ID,
FIELD_PASSWORD,
FIELD_PASSWORD_FILE);
final String authID = LDAPConnectionDetailsJSONSpecification.getString(o,
FIELD_AUTHENTICATION_ID, null);
if (authID == null)
{
throw new LDAPException(ResultCode.PARAM_ERROR,
ERR_AUTH_DETAILS_MISSING_REQUIRED_FIELD_FOR_AUTH_TYPE.get(
FIELD_AUTHENTICATION_ID, authType));
}
final String password = getPassword(o, authType, false);
bindRequest = new CRAMMD5BindRequest(authID, password);
}
else if (loweAuthType.equals("digest-md5") ||
loweAuthType.equals("digestmd5"))
{
validateAllowedFields(o, authType,
FIELD_AUTHENTICATION_ID,
FIELD_AUTHORIZATION_ID,
FIELD_PASSWORD,
FIELD_PASSWORD_FILE,
FIELD_QOP,
FIELD_REALM);
final String authID = LDAPConnectionDetailsJSONSpecification.getString(o,
FIELD_AUTHENTICATION_ID, null);
if (authID == null)
{
throw new LDAPException(ResultCode.PARAM_ERROR,
ERR_AUTH_DETAILS_MISSING_REQUIRED_FIELD_FOR_AUTH_TYPE.get(
FIELD_AUTHENTICATION_ID, authType));
}
final String password = getPassword(o, authType, false);
final DIGESTMD5BindRequestProperties properties =
new DIGESTMD5BindRequestProperties(authID, password);
properties.setAuthorizationID(
LDAPConnectionDetailsJSONSpecification.getString(o,
FIELD_AUTHORIZATION_ID, null));
properties.setRealm(LDAPConnectionDetailsJSONSpecification.getString(o,
FIELD_REALM, null));
properties.setAllowedQoP(getAllowedQoP(o));
bindRequest = new DIGESTMD5BindRequest(properties);
}
else if (loweAuthType.equals("external"))
{
validateAllowedFields(o, authType,
FIELD_AUTHORIZATION_ID);
final String authzID = LDAPConnectionDetailsJSONSpecification.getString(o,
FIELD_AUTHORIZATION_ID, null);
bindRequest = new EXTERNALBindRequest(authzID);
}
else if (loweAuthType.equals("gssapi") ||
loweAuthType.equals("gss-api"))
{
validateAllowedFields(o, authType,
FIELD_AUTHENTICATION_ID,
FIELD_AUTHORIZATION_ID,
FIELD_PASSWORD,
FIELD_PASSWORD_FILE,
FIELD_CONFIG_FILE_PATH,
FIELD_KDC_ADDRESS,
FIELD_QOP,
FIELD_REALM,
FIELD_RENEW_TGT,
FIELD_REQUIRE_CACHED_CREDENTIALS,
FIELD_TICKET_CACHE_PATH,
FIELD_USE_SUBJECT_CREDS_ONLY,
FIELD_USE_TICKET_CACHE);
final String authID = LDAPConnectionDetailsJSONSpecification.getString(o,
FIELD_AUTHENTICATION_ID, null);
if (authID == null)
{
throw new LDAPException(ResultCode.PARAM_ERROR,
ERR_AUTH_DETAILS_MISSING_REQUIRED_FIELD_FOR_AUTH_TYPE.get(
FIELD_AUTHENTICATION_ID, authType));
}
final String password = getPassword(o, authType, true);
final GSSAPIBindRequestProperties properties =
new GSSAPIBindRequestProperties(authID, password);
properties.setAuthorizationID(
LDAPConnectionDetailsJSONSpecification.getString(o,
FIELD_AUTHORIZATION_ID, null));
properties.setRealm(LDAPConnectionDetailsJSONSpecification.getString(o,
FIELD_REALM, null));
properties.setAllowedQoP(getAllowedQoP(o));
properties.setConfigFilePath(
LDAPConnectionDetailsJSONSpecification.getString(o,
FIELD_CONFIG_FILE_PATH, null));
properties.setKDCAddress(
LDAPConnectionDetailsJSONSpecification.getString(o,
FIELD_KDC_ADDRESS, null));
properties.setRenewTGT(
LDAPConnectionDetailsJSONSpecification.getBoolean(o,
FIELD_RENEW_TGT, false));
properties.setRequireCachedCredentials(
LDAPConnectionDetailsJSONSpecification.getBoolean(o,
FIELD_REQUIRE_CACHED_CREDENTIALS, false));
properties.setTicketCachePath(
LDAPConnectionDetailsJSONSpecification.getString(o,
FIELD_TICKET_CACHE_PATH, null));
properties.setUseSubjectCredentialsOnly(
LDAPConnectionDetailsJSONSpecification.getBoolean(o,
FIELD_USE_SUBJECT_CREDS_ONLY, true));
properties.setUseTicketCache(
LDAPConnectionDetailsJSONSpecification.getBoolean(o,
FIELD_USE_TICKET_CACHE, true));
if ((password == null) && (! properties.requireCachedCredentials()))
{
throw new LDAPException(ResultCode.PARAM_ERROR,
ERR_AUTH_DETAILS_MISSING_GSSAPI_PASSWORD.get(FIELD_PASSWORD,
FIELD_PASSWORD_FILE, authType,
FIELD_REQUIRE_CACHED_CREDENTIALS));
}
bindRequest = new GSSAPIBindRequest(properties);
}
else if (loweAuthType.equals("plain"))
{
validateAllowedFields(o, authType,
FIELD_AUTHENTICATION_ID,
FIELD_AUTHORIZATION_ID,
FIELD_PASSWORD,
FIELD_PASSWORD_FILE);
final String authID = LDAPConnectionDetailsJSONSpecification.getString(o,
FIELD_AUTHENTICATION_ID, null);
if (authID == null)
{
throw new LDAPException(ResultCode.PARAM_ERROR,
ERR_AUTH_DETAILS_MISSING_REQUIRED_FIELD_FOR_AUTH_TYPE.get(
FIELD_AUTHENTICATION_ID, authType));
}
final String authzID = LDAPConnectionDetailsJSONSpecification.getString(o,
FIELD_AUTHORIZATION_ID, null);
final String password = getPassword(o, authType, false);
bindRequest = new PLAINBindRequest(authID, authzID, password);
}
else
{
throw new LDAPException(ResultCode.PARAM_ERROR,
ERR_AUTH_DETAILS_UNRECOGNIZED_TYPE.get(authType));
}
}
/**
* Retrieves the bind request created from the authentication details.
*
* @return The bind request created from the authentication details.
*/
BindRequest getBindRequest()
{
return bindRequest;
}
/**
* Validates that all of the provided fields are allowed for use in
* conjunction with the specified authentication type.
*
* @param o The JSON object to process.
* @param authType The name of the authentication type.
* @param allowedFields The names of the fields allowed for use with the
* specified authentication type.
*
* @throws LDAPException If the provided object contains any field not
* permitted in conjunction with the specified
* authentication type.
*/
private static void validateAllowedFields(final JSONObject o,
final String authType,
final String... allowedFields)
throws LDAPException
{
final HashSet s = new HashSet(Arrays.asList(allowedFields));
for (final String fieldName : o.getFields().keySet())
{
if (fieldName.equals(FIELD_AUTHENTICATION_TYPE))
{
continue;
}
if (! s.contains(fieldName))
{
throw new LDAPException(ResultCode.PARAM_ERROR,
ERR_AUTH_DETAILS_FIELD_NOT_PERMITTED_FOR_AUTH_TYPE.get(fieldName,
authType));
}
}
}
/**
* Retrieves a password from the provided JSON object. The password must
* either be directly contained in the object's password field, or it must be
* in a file referenced by the object's password-file object.
*
* @param o The JSON object to process.
* @param authType The authentication type.
* @param optional Indicates whether the password should be optional for the
* bind request.
*
* @return The password, or {@code null} if no password was provided and the
* password is optional.
*
* @throws LDAPException If no password is available or a problem is
* encountered while trying to read the password from
* a file.
*/
private static String getPassword(final JSONObject o, final String authType,
final boolean optional)
throws LDAPException
{
final String password = LDAPConnectionDetailsJSONSpecification.getString(o,
FIELD_PASSWORD, null);
if (password != null)
{
LDAPConnectionDetailsJSONSpecification.rejectConflictingFields(o,
FIELD_PASSWORD, FIELD_PASSWORD_FILE);
return password;
}
final String path = LDAPConnectionDetailsJSONSpecification.getString(o,
FIELD_PASSWORD_FILE, null);
if (path == null)
{
if (optional)
{
return null;
}
else
{
throw new LDAPException(ResultCode.PARAM_ERROR,
ERR_AUTH_DETAILS_NO_PASSWORD.get(FIELD_PASSWORD,
FIELD_PASSWORD_FILE, authType));
}
}
return LDAPConnectionDetailsJSONSpecification.getStringFromFile(path,
FIELD_PASSWORD_FILE);
}
/**
* Retrieves the allowed quality of protection values from the provided JSON
* object.
*
* @param o The JSON object to process.
*
* @return A set containing the allowed quality of protection values.
*
* @throws LDAPException If no password is available or a problem is
* encountered while trying to read the password from
* a file.
*/
private static List getAllowedQoP(final JSONObject o)
throws LDAPException
{
final JSONValue v = o.getField(FIELD_QOP);
if (v == null)
{
return Collections.singletonList(SASLQualityOfProtection.AUTH);
}
if (v instanceof JSONString)
{
return SASLQualityOfProtection.decodeQoPList(
((JSONString) v).stringValue());
}
else if (v instanceof JSONArray)
{
final JSONArray a = (JSONArray) v;
final ArrayList qopList =
new ArrayList(a.size());
for (final JSONValue av : a.getValues())
{
if (av instanceof JSONString)
{
final SASLQualityOfProtection qop = SASLQualityOfProtection.forName(
((JSONString) av).stringValue());
if (qop == null)
{
throw new LDAPException(ResultCode.PARAM_ERROR,
ERR_AUTH_DETAILS_INVALID_QOP.get(FIELD_QOP));
}
else
{
qopList.add(qop);
}
}
else
{
throw new LDAPException(ResultCode.PARAM_ERROR,
ERR_AUTH_DETAILS_INVALID_QOP.get(FIELD_QOP));
}
}
return qopList;
}
else
{
throw new LDAPException(ResultCode.PARAM_ERROR,
ERR_AUTH_DETAILS_INVALID_QOP.get(FIELD_QOP));
}
}
}