org.wildfly.security.auth.client.AuthenticationConfiguration Maven / Gradle / Ivy
/*
* JBoss, Home of Professional Open Source.
* Copyright 2014 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* 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.
*/
package org.wildfly.security.auth.client;
import static java.security.AccessController.doPrivileged;
import static java.security.AccessController.getContext;
import static org.wildfly.security.auth.client._private.ElytronMessages.log;
import static org.wildfly.security.provider.util.ProviderUtil.INSTALLED_PROVIDERS;
import java.io.IOException;
import java.net.URI;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.PrivilegedAction;
import java.security.Provider;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.InvalidKeySpecException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.BiPredicate;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
import javax.net.ssl.SSLSession;
import javax.net.ssl.X509KeyManager;
import javax.net.ssl.X509TrustManager;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.ChoiceCallback;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.TextInputCallback;
import javax.security.auth.callback.TextOutputCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.x500.X500Principal;
import javax.security.sasl.RealmCallback;
import javax.security.sasl.RealmChoiceCallback;
import javax.security.sasl.SaslClient;
import javax.security.sasl.SaslClientFactory;
import javax.security.sasl.SaslException;
import org.ietf.jgss.GSSCredential;
import org.ietf.jgss.Oid;
import org.wildfly.common.Assert;
import org.wildfly.common.annotation.NotNull;
import org.wildfly.common.array.Arrays2;
import org.wildfly.common.iteration.CodePointIterator;
import org.wildfly.security.FixedSecurityFactory;
import org.wildfly.security.SecurityFactory;
import org.wildfly.security.auth.callback.CallbackUtil;
import org.wildfly.security.auth.callback.ChannelBindingCallback;
import org.wildfly.security.auth.callback.CredentialCallback;
import org.wildfly.security.auth.callback.EvidenceVerifyCallback;
import org.wildfly.security.auth.callback.ParameterCallback;
import org.wildfly.security.auth.callback.PasswordResetCallback;
import org.wildfly.security.auth.callback.SSLCallback;
import org.wildfly.security.auth.callback.TrustedAuthoritiesCallback;
import org.wildfly.security.auth.principal.AnonymousPrincipal;
import org.wildfly.security.auth.principal.NamePrincipal;
import org.wildfly.security.auth.server.IdentityCredentials;
import org.wildfly.security.auth.server.NameRewriter;
import org.wildfly.security.auth.server.SecurityDomain;
import org.wildfly.security.credential.AlgorithmCredential;
import org.wildfly.security.credential.BearerTokenCredential;
import org.wildfly.security.credential.Credential;
import org.wildfly.security.credential.GSSKerberosCredential;
import org.wildfly.security.credential.PasswordCredential;
import org.wildfly.security.credential.X509CertificateChainPrivateCredential;
import org.wildfly.security.credential.source.CredentialSource;
import org.wildfly.security.credential.source.impl.CredentialStoreCredentialSource;
import org.wildfly.security.credential.source.impl.FactoryCredentialSource;
import org.wildfly.security.credential.source.impl.KeyStoreCredentialSource;
import org.wildfly.security.credential.source.impl.LocalKerberosCredentialSource;
import org.wildfly.security.credential.store.CredentialStore;
import org.wildfly.security.evidence.X509PeerCertificateChainEvidence;
import org.wildfly.security.password.Password;
import org.wildfly.security.password.PasswordFactory;
import org.wildfly.security.password.TwoWayPassword;
import org.wildfly.security.password.interfaces.ClearPassword;
import org.wildfly.security.password.interfaces.MaskedPassword;
import org.wildfly.security.password.spec.ClearPasswordSpec;
import org.wildfly.security.password.spec.MaskedPasswordSpec;
import org.wildfly.security.provider.util.ProviderFactory;
import org.wildfly.security.provider.util.ProviderServiceLoaderSupplier;
import org.wildfly.security.sasl.SaslMechanismSelector;
import org.wildfly.security.sasl.util.FilterMechanismSaslClientFactory;
import org.wildfly.security.sasl.util.LocalPrincipalSaslClientFactory;
import org.wildfly.security.sasl.util.PrivilegedSaslClientFactory;
import org.wildfly.security.sasl.util.PropertiesSaslClientFactory;
import org.wildfly.security.sasl.util.ProtocolSaslClientFactory;
import org.wildfly.security.sasl.util.SSLSaslClientFactory;
import org.wildfly.security.sasl.util.SaslMechanismInformation;
import org.wildfly.security.sasl.util.SecurityProviderSaslClientFactory;
import org.wildfly.security.sasl.util.ServerNameSaslClientFactory;
import org.wildfly.security.ssl.SSLConnection;
import org.wildfly.security.ssl.SSLUtils;
import org.wildfly.security.x500.TrustedAuthority;
/**
* A configuration which controls how authentication is performed.
*
* @author David M. Lloyd
* @author Darran Lofthouse
*/
public final class AuthenticationConfiguration {
// constants
private static final Principal[] NO_PRINCIPALS = new Principal[0];
private static final Callback[] NO_CALLBACKS = new Callback[0];
private static final String[] NO_STRINGS = new String[0];
private static final EnumSet NO_CALLBACK_KINDS = EnumSet.noneOf(CallbackKind.class);
private static final int SET_PRINCIPAL = 0;
private static final int SET_HOST = 1;
private static final int SET_PROTOCOL = 2;
private static final int SET_REALM = 3;
private static final int SET_AUTHZ_PRINCIPAL = 4;
private static final int SET_FWD_AUTH_NAME_DOMAIN = 5;
private static final int SET_USER_CBH = 6;
private static final int SET_USER_CB_KINDS = 7;
private static final int SET_CRED_SOURCE = 8;
private static final int SET_PROVIDER_SUPPLIER = 9;
private static final int SET_KEY_MGR_FAC = 10;
private static final int SET_SASL_SELECTOR = 11;
private static final int SET_FWD_AUTH_CRED_DOMAIN = 12;
private static final int SET_PRINCIPAL_RW = 13;
private static final int SET_SASL_FAC_SUP = 14;
private static final int SET_PARAM_SPECS = 15;
private static final int SET_TRUST_MGR_FAC = 16;
private static final int SET_SASL_MECH_PROPS = 17;
private static final int SET_ACCESS_CTXT = 18;
private static final int SET_CALLBACK_INTERCEPT = 19;
private static final int SET_SASL_PROTOCOL = 20;
private static final int SET_FWD_AUTHZ_NAME_DOMAIN = 21;
private static final int SET_WEBSERVICES_PROPS = 22;
private static final String JBOSS_LOCAL_USER_QUIET_AUTH = "wildfly.sasl.local-user.quiet-auth";
private static final String JBOSS_LOCAL_USER_LEGACY_QUIET_AUTH = "jboss.sasl.local-user.quiet-auth";
private static final Supplier DEFAULT_PROVIDER_SUPPLIER = ProviderFactory.getDefaultProviderSupplier(AuthenticationConfiguration.class.getClassLoader());
static final String WILDFLY_ELYTRON_CAPTURE_ACCESS_CONTROL_CONTEXT_PROPERTY_NAME = "wildfly.elytron.capture.access.control.context";
static final boolean WILDFLY_ELYTRON_CAPTURE_ACCESS_CONTROL_CONTEXT_PROPERTY;
static {
WILDFLY_ELYTRON_CAPTURE_ACCESS_CONTROL_CONTEXT_PROPERTY = AccessController.doPrivileged(new PrivilegedAction() {
@Override
public Boolean run() {
return Boolean.parseBoolean(System.getProperty(WILDFLY_ELYTRON_CAPTURE_ACCESS_CONTROL_CONTEXT_PROPERTY_NAME, "true"));
}
});
}
/**
* An empty configuration which can be used as the basis for any configuration. This configuration supports no
* remapping of any kind, and always uses an anonymous principal.
* @deprecated to obtain empty configuration use {@link #empty()} method instead
*/
@Deprecated
public static final AuthenticationConfiguration EMPTY = new AuthenticationConfiguration();
/**
* An empty configuration which can be used as the basis for any configuration. This configuration supports no
* remapping of any kind, and always uses an anonymous principal.
*/
public static AuthenticationConfiguration empty() {
return EMPTY;
}
private volatile SaslClientFactory saslClientFactory = null;
private int hashCode;
private String toString;
final AccessControlContext capturedAccessContext;
@NotNull final Principal principal;
final String setHost;
final String setProtocol;
final String setRealm;
final Principal setAuthzPrincipal;
final SecurityDomain authenticationNameForwardSecurityDomain;
final SecurityDomain authenticationCredentialsForwardSecurityDomain;
final SecurityDomain authorizationNameForwardSecurityDomain;
final CallbackHandler userCallbackHandler;
final EnumSet userCallbackKinds;
final CredentialSource credentialSource;
final int setPort;
final Supplier providerSupplier;
final SecurityFactory keyManagerFactory;
final SaslMechanismSelector saslMechanismSelector;
final Function principalRewriter;
final Supplier saslClientFactorySupplier;
final List parameterSpecs;
final SecurityFactory trustManagerFactory;
final Map saslMechanismProperties;
final Predicate callbackIntercept;
final String saslProtocol;
final Map webServicesProperties;
// constructors
/**
* Construct the empty configuration instance.
*/
private AuthenticationConfiguration() {
this.capturedAccessContext = null;
this.principal = AnonymousPrincipal.getInstance();
this.setHost = null;
this.setProtocol = null;
this.setRealm = null;
this.setAuthzPrincipal = null;
this.authenticationNameForwardSecurityDomain = null;
this.authenticationCredentialsForwardSecurityDomain = null;
this.authorizationNameForwardSecurityDomain = null;
this.userCallbackHandler = null;
this.userCallbackKinds = NO_CALLBACK_KINDS;
this.credentialSource = IdentityCredentials.NONE;
this.setPort = -1;
this.providerSupplier = DEFAULT_PROVIDER_SUPPLIER;
this.keyManagerFactory = null;
this.saslMechanismSelector = null;
this.principalRewriter = null;
this.saslClientFactorySupplier = null;
this.parameterSpecs = Collections.emptyList();
this.trustManagerFactory = null;
this.saslMechanismProperties = Collections.singletonMap(JBOSS_LOCAL_USER_QUIET_AUTH, "true");
this.callbackIntercept = null;
this.saslProtocol = null;
this.webServicesProperties = null;
}
/**
* Copy constructor for mutating one object field. It's not pretty but the alternative (many constructors) is much
* worse.
*
* @param original the original configuration (must not be {@code null})
* @param what the field to mutate
* @param value the field value to set
*/
@SuppressWarnings("unchecked")
private AuthenticationConfiguration(final AuthenticationConfiguration original, final int what, final Object value) {
this.capturedAccessContext = what == SET_ACCESS_CTXT ? (AccessControlContext) value : original.capturedAccessContext;
this.principal = what == SET_PRINCIPAL ? (Principal) value : original.principal;
this.setHost = what == SET_HOST ? (String) value : original.setHost;
this.setProtocol = what == SET_PROTOCOL ? (String) value : original.setProtocol;
this.setRealm = what == SET_REALM ? (String) value : original.setRealm;
this.setAuthzPrincipal = what == SET_AUTHZ_PRINCIPAL ? (Principal) value : original.setAuthzPrincipal;
this.authenticationNameForwardSecurityDomain = what == SET_FWD_AUTH_NAME_DOMAIN ? (SecurityDomain) value : original.authenticationNameForwardSecurityDomain;
this.authenticationCredentialsForwardSecurityDomain = what == SET_FWD_AUTH_CRED_DOMAIN ? (SecurityDomain) value : original.authenticationCredentialsForwardSecurityDomain;
this.authorizationNameForwardSecurityDomain = what == SET_FWD_AUTHZ_NAME_DOMAIN ? (SecurityDomain) value : original.authorizationNameForwardSecurityDomain;
this.userCallbackHandler = what == SET_USER_CBH ? (CallbackHandler) value : original.userCallbackHandler;
this.userCallbackKinds = (what == SET_USER_CB_KINDS ? (EnumSet) value : original.userCallbackKinds).clone();
this.credentialSource = what == SET_CRED_SOURCE ? (CredentialSource) value : original.credentialSource;
this.setPort = original.setPort;
this.providerSupplier = what == SET_PROVIDER_SUPPLIER ? (Supplier) value : original.providerSupplier;
this.keyManagerFactory = what == SET_KEY_MGR_FAC ? (SecurityFactory) value : original.keyManagerFactory;
this.saslMechanismSelector = what == SET_SASL_SELECTOR ? (SaslMechanismSelector) value : original.saslMechanismSelector;
this.principalRewriter = what == SET_PRINCIPAL_RW ? (Function) value : original.principalRewriter;
this.saslClientFactorySupplier = what == SET_SASL_FAC_SUP ? (Supplier) value : original.saslClientFactorySupplier;
this.parameterSpecs = what == SET_PARAM_SPECS ? (List) value : original.parameterSpecs;
this.trustManagerFactory = what == SET_TRUST_MGR_FAC ? (SecurityFactory) value : original.trustManagerFactory;
this.saslMechanismProperties = what == SET_SASL_MECH_PROPS ? (Map) value : original.saslMechanismProperties;
this.callbackIntercept = what == SET_CALLBACK_INTERCEPT ? (Predicate) value : original.callbackIntercept;
this.saslProtocol = what == SET_SASL_PROTOCOL ? (String) value : original.saslProtocol;
this.webServicesProperties = what == SET_WEBSERVICES_PROPS ? (Map) value : original.webServicesProperties;
sanitazeOnMutation(what);
}
/**
* Copy constructor for mutating two object fields. It's not pretty but the alternative (many constructors) is much
* worse.
*
* @param original the original configuration (must not be {@code null})
* @param what1 the field to mutate
* @param value1 the field value to set
* @param what2 the field to mutate
* @param value2 the field value to set
*/
@SuppressWarnings("unchecked")
private AuthenticationConfiguration(final AuthenticationConfiguration original, final int what1, final Object value1, final int what2, final Object value2) {
this.capturedAccessContext = what1 == SET_ACCESS_CTXT ? (AccessControlContext) value1 : what2 == SET_ACCESS_CTXT ? (AccessControlContext) value2 : original.capturedAccessContext;
this.principal = what1 == SET_PRINCIPAL ? (Principal) value1 : what2 == SET_PRINCIPAL ? (Principal) value2 : original.principal;
this.setHost = what1 == SET_HOST ? (String) value1 : what2 == SET_HOST ? (String) value2 : original.setHost;
this.setProtocol = what1 == SET_PROTOCOL ? (String) value1 : what2 == SET_PROTOCOL ? (String) value2 : original.setProtocol;
this.setRealm = what1 == SET_REALM ? (String) value1 : what2 == SET_REALM ? (String) value2 : original.setRealm;
this.setAuthzPrincipal = what1 == SET_AUTHZ_PRINCIPAL ? (Principal) value1 : what2 == SET_AUTHZ_PRINCIPAL ? (Principal) value2 : original.setAuthzPrincipal;
this.authenticationNameForwardSecurityDomain = what1 == SET_FWD_AUTH_NAME_DOMAIN ? (SecurityDomain) value1 : what2 == SET_FWD_AUTH_NAME_DOMAIN ? (SecurityDomain) value2 : original.authenticationNameForwardSecurityDomain;
this.authenticationCredentialsForwardSecurityDomain = what1 == SET_FWD_AUTH_CRED_DOMAIN ? (SecurityDomain) value1 : what2 == SET_FWD_AUTH_CRED_DOMAIN ? (SecurityDomain) value2 : original.authenticationCredentialsForwardSecurityDomain;
this.authorizationNameForwardSecurityDomain = what1 == SET_FWD_AUTHZ_NAME_DOMAIN ? (SecurityDomain) value1 : what2 == SET_FWD_AUTHZ_NAME_DOMAIN ? (SecurityDomain) value2 : original.authorizationNameForwardSecurityDomain;
this.userCallbackHandler = what1 == SET_USER_CBH ? (CallbackHandler) value1 : what2 == SET_USER_CBH ? (CallbackHandler) value2 : original.userCallbackHandler;
this.userCallbackKinds = (what1 == SET_USER_CB_KINDS ? (EnumSet) value1 : what2 == SET_USER_CB_KINDS ? (EnumSet) value2 : original.userCallbackKinds).clone();
this.credentialSource = what1 == SET_CRED_SOURCE ? (CredentialSource) value1 : what2 == SET_CRED_SOURCE ? (CredentialSource) value2 : original.credentialSource;
this.setPort = original.setPort;
this.providerSupplier = what1 == SET_PROVIDER_SUPPLIER ? (Supplier) value1 : what2 == SET_PROVIDER_SUPPLIER ? (Supplier) value2 : original.providerSupplier;
this.keyManagerFactory = what1 == SET_KEY_MGR_FAC ? (SecurityFactory) value1 : what2 == SET_KEY_MGR_FAC ? (SecurityFactory) value2 : original.keyManagerFactory;
this.saslMechanismSelector = what1 == SET_SASL_SELECTOR ? (SaslMechanismSelector) value1 : what2 == SET_SASL_SELECTOR ? (SaslMechanismSelector) value2 : original.saslMechanismSelector;
this.principalRewriter = what1 == SET_PRINCIPAL_RW ? (Function) value1 : what2 == SET_PRINCIPAL_RW ? (Function) value2 : original.principalRewriter;
this.saslClientFactorySupplier = what1 == SET_SASL_FAC_SUP ? (Supplier) value1 : what2 == SET_SASL_FAC_SUP ? (Supplier) value2 : original.saslClientFactorySupplier;
this.parameterSpecs = what1 == SET_PARAM_SPECS ? (List) value1 : what2 == SET_PARAM_SPECS ? (List) value2 : original.parameterSpecs;
this.trustManagerFactory = what1 == SET_TRUST_MGR_FAC ? (SecurityFactory) value1 : what2 == SET_TRUST_MGR_FAC ? (SecurityFactory) value2 : original.trustManagerFactory;
this.saslMechanismProperties = what1 == SET_SASL_MECH_PROPS ? (Map) value1 : what2 == SET_SASL_MECH_PROPS ? (Map) value2 : original.saslMechanismProperties;
this.callbackIntercept = what1 == SET_CALLBACK_INTERCEPT ? (Predicate) value1 : what2 == SET_CALLBACK_INTERCEPT ? (Predicate) value2 : original.callbackIntercept;
this.saslProtocol = what1 == SET_SASL_PROTOCOL ? (String) value1 : what2 == SET_SASL_PROTOCOL ? (String) value2 : original.saslProtocol;
this.webServicesProperties = what1 == SET_WEBSERVICES_PROPS ? (Map) value1 : what2 == SET_WEBSERVICES_PROPS ? (Map) value2 : original.webServicesProperties;
sanitazeOnMutation(what1);
sanitazeOnMutation(what2);
}
/**
* Copy constructor for mutating three object fields.
*
* @param original the original configuration (must not be {@code null})
* @param what1 the field to mutate
* @param value1 the field value to set
* @param what2 the field to mutate
* @param value2 the field value to set
* @param what3 the field to mutate
* @param value3 the field value to set
*/
@SuppressWarnings("unchecked")
private AuthenticationConfiguration(final AuthenticationConfiguration original, final int what1, final Object value1, final int what2, final Object value2, final int what3, final Object value3) {
this.capturedAccessContext = what1 == SET_ACCESS_CTXT ? (AccessControlContext) value1 : what2 == SET_ACCESS_CTXT ? (AccessControlContext) value2 : what3 == SET_ACCESS_CTXT ? (AccessControlContext) value3 : original.capturedAccessContext;
this.principal = what1 == SET_PRINCIPAL ? (Principal) value1 : what2 == SET_PRINCIPAL ? (Principal) value2 : what3 == SET_PRINCIPAL ? (Principal) value3 : original.principal;
this.setHost = what1 == SET_HOST ? (String) value1 : what2 == SET_HOST ? (String) value2 : what3 == SET_HOST ? (String) value3 :original.setHost;
this.setProtocol = what1 == SET_PROTOCOL ? (String) value1 : what2 == SET_PROTOCOL ? (String) value2 : what3 == SET_PROTOCOL ? (String) value3 : original.setProtocol;
this.setRealm = what1 == SET_REALM ? (String) value1 : what2 == SET_REALM ? (String) value2 : what3 == SET_REALM ? (String) value3 : original.setRealm;
this.setAuthzPrincipal = what1 == SET_AUTHZ_PRINCIPAL ? (Principal) value1 : what2 == SET_AUTHZ_PRINCIPAL ? (Principal) value2 : what3 == SET_AUTHZ_PRINCIPAL ? (Principal) value3 : original.setAuthzPrincipal;
this.authenticationNameForwardSecurityDomain = what1 == SET_FWD_AUTH_NAME_DOMAIN ? (SecurityDomain) value1 : what2 == SET_FWD_AUTH_NAME_DOMAIN ? (SecurityDomain) value2 : what3 == SET_FWD_AUTH_NAME_DOMAIN ? (SecurityDomain) value3 : original.authenticationNameForwardSecurityDomain;
this.authenticationCredentialsForwardSecurityDomain = what1 == SET_FWD_AUTH_CRED_DOMAIN ? (SecurityDomain) value1 : what2 == SET_FWD_AUTH_CRED_DOMAIN ? (SecurityDomain) value2 : what3 == SET_FWD_AUTH_CRED_DOMAIN ? (SecurityDomain) value3 : original.authenticationCredentialsForwardSecurityDomain;
this.authorizationNameForwardSecurityDomain = what1 == SET_FWD_AUTHZ_NAME_DOMAIN ? (SecurityDomain) value1 : what2 == SET_FWD_AUTHZ_NAME_DOMAIN ? (SecurityDomain) value2 : what3 == SET_FWD_AUTHZ_NAME_DOMAIN ? (SecurityDomain) value3 : original.authorizationNameForwardSecurityDomain;
this.userCallbackHandler = what1 == SET_USER_CBH ? (CallbackHandler) value1 : what2 == SET_USER_CBH ? (CallbackHandler) value2 : what3 == SET_USER_CBH ? (CallbackHandler) value3 : original.userCallbackHandler;
this.userCallbackKinds = (what1 == SET_USER_CB_KINDS ? (EnumSet) value1 : what2 == SET_USER_CB_KINDS ? (EnumSet) value2 : what3 == SET_USER_CB_KINDS ? (EnumSet) value3 : original.userCallbackKinds).clone();
this.credentialSource = what1 == SET_CRED_SOURCE ? (CredentialSource) value1 : what2 == SET_CRED_SOURCE ? (CredentialSource) value2 : what3 == SET_CRED_SOURCE ? (CredentialSource) value3 : original.credentialSource;
this.setPort = original.setPort;
this.providerSupplier = what1 == SET_PROVIDER_SUPPLIER ? (Supplier) value1 : what2 == SET_PROVIDER_SUPPLIER ? (Supplier) value2 : what3 == SET_PROVIDER_SUPPLIER ? (Supplier) value3 : original.providerSupplier;
this.keyManagerFactory = what1 == SET_KEY_MGR_FAC ? (SecurityFactory) value1 : what2 == SET_KEY_MGR_FAC ? (SecurityFactory) value2 : what3 == SET_KEY_MGR_FAC ? (SecurityFactory) value3 : original.keyManagerFactory;
this.saslMechanismSelector = what1 == SET_SASL_SELECTOR ? (SaslMechanismSelector) value1 : what2 == SET_SASL_SELECTOR ? (SaslMechanismSelector) value2 : what3 == SET_SASL_SELECTOR ? (SaslMechanismSelector) value3 : original.saslMechanismSelector;
this.principalRewriter = what1 == SET_PRINCIPAL_RW ? (Function) value1 : what2 == SET_PRINCIPAL_RW ? (Function) value2 : what3 == SET_PRINCIPAL_RW ? (Function) value3 : original.principalRewriter;
this.saslClientFactorySupplier = what1 == SET_SASL_FAC_SUP ? (Supplier) value1 : what2 == SET_SASL_FAC_SUP ? (Supplier) value2 : what3 == SET_SASL_FAC_SUP ? (Supplier) value3 : original.saslClientFactorySupplier;
this.parameterSpecs = what1 == SET_PARAM_SPECS ? (List) value1 : what2 == SET_PARAM_SPECS ? (List) value2 : what3 == SET_PARAM_SPECS ? (List) value3 : original.parameterSpecs;
this.trustManagerFactory = what1 == SET_TRUST_MGR_FAC ? (SecurityFactory) value1 : what2 == SET_TRUST_MGR_FAC ? (SecurityFactory) value2 : what3 == SET_TRUST_MGR_FAC ? (SecurityFactory) value3 : original.trustManagerFactory;
this.saslMechanismProperties = what1 == SET_SASL_MECH_PROPS ? (Map) value1 : what2 == SET_SASL_MECH_PROPS ? (Map) value2 : what3 == SET_SASL_MECH_PROPS ? (Map) value3 : original.saslMechanismProperties;
this.callbackIntercept = what1 == SET_CALLBACK_INTERCEPT ? (Predicate) value1 : what2 == SET_CALLBACK_INTERCEPT ? (Predicate) value2 : what3 == SET_CALLBACK_INTERCEPT ? (Predicate) value3 : original.callbackIntercept;
this.saslProtocol = what1 == SET_SASL_PROTOCOL ? (String) value1 : what2 == SET_SASL_PROTOCOL ? (String) value2 : what3 == SET_SASL_PROTOCOL ? (String) value3 : original.saslProtocol;
this.webServicesProperties = what1 == SET_WEBSERVICES_PROPS ? (Map) value1 : what2 == SET_WEBSERVICES_PROPS ? (Map) value2 : what3 == SET_WEBSERVICES_PROPS ? (Map) value3 : original.webServicesProperties;
sanitazeOnMutation(what1);
sanitazeOnMutation(what2);
sanitazeOnMutation(what3);
}
/**
* Copy constructor for mutating the port number.
*
* @param original the original configuration (must not be {@code null})
* @param port the port number
*/
private AuthenticationConfiguration(final AuthenticationConfiguration original, final int port) {
this.capturedAccessContext = original.capturedAccessContext;
this.principal = original.principal;
this.setHost = original.setHost;
this.setProtocol = original.setProtocol;
this.setRealm = original.setRealm;
this.setAuthzPrincipal = original.setAuthzPrincipal;
this.authenticationNameForwardSecurityDomain = original.authenticationNameForwardSecurityDomain;
this.authenticationCredentialsForwardSecurityDomain = original.authenticationCredentialsForwardSecurityDomain;
this.authorizationNameForwardSecurityDomain = original.authorizationNameForwardSecurityDomain;
this.userCallbackHandler = original.userCallbackHandler;
this.userCallbackKinds = original.userCallbackKinds;
this.credentialSource = original.credentialSource;
this.setPort = port;
this.providerSupplier = original.providerSupplier;
this.keyManagerFactory = original.keyManagerFactory;
this.saslMechanismSelector = original.saslMechanismSelector;
this.principalRewriter = original.principalRewriter;
this.saslClientFactorySupplier = original.saslClientFactorySupplier;
this.parameterSpecs = original.parameterSpecs;
this.trustManagerFactory = original.trustManagerFactory;
this.saslMechanismProperties = original.saslMechanismProperties;
this.callbackIntercept = original.callbackIntercept;
this.saslProtocol = original.saslProtocol;
this.webServicesProperties = original.webServicesProperties;
}
private AuthenticationConfiguration(final AuthenticationConfiguration original, final AuthenticationConfiguration other) {
this.capturedAccessContext = getOrDefault(other.capturedAccessContext, original.capturedAccessContext);
this.principal = other.principal instanceof AnonymousPrincipal ? original.principal : other.principal;
this.setHost = getOrDefault(other.setHost, original.setHost);
this.setProtocol = getOrDefault(other.setProtocol, original.setProtocol);
this.setRealm = getOrDefault(other.setRealm, original.setRealm);
this.setAuthzPrincipal = getOrDefault(other.setAuthzPrincipal, original.setAuthzPrincipal);
this.authenticationNameForwardSecurityDomain = getOrDefault(other.authenticationNameForwardSecurityDomain, original.authenticationNameForwardSecurityDomain);
this.authenticationCredentialsForwardSecurityDomain = getOrDefault(other.authenticationCredentialsForwardSecurityDomain, original.authenticationCredentialsForwardSecurityDomain);
this.authorizationNameForwardSecurityDomain = getOrDefault(other.authorizationNameForwardSecurityDomain, original.authorizationNameForwardSecurityDomain);
this.userCallbackHandler = getOrDefault(other.userCallbackHandler, original.userCallbackHandler);
this.userCallbackKinds = getOrDefault(other.userCallbackKinds, original.userCallbackKinds).clone();
this.credentialSource = other.credentialSource == IdentityCredentials.NONE ? original.credentialSource : other.credentialSource;
this.setPort = getOrDefault(other.setPort, original.setPort);
this.providerSupplier = getOrDefault(other.providerSupplier, original.providerSupplier);
this.keyManagerFactory = getOrDefault(other.keyManagerFactory, original.keyManagerFactory);
this.saslMechanismSelector = getOrDefault(other.saslMechanismSelector, original.saslMechanismSelector);
this.principalRewriter = getOrDefault(other.principalRewriter, original.principalRewriter);
this.saslClientFactorySupplier = getOrDefault(other.saslClientFactorySupplier, original.saslClientFactorySupplier);
this.parameterSpecs = getOrDefault(other.parameterSpecs, original.parameterSpecs);
this.trustManagerFactory = getOrDefault(other.trustManagerFactory, original.trustManagerFactory);
this.saslMechanismProperties = getOrDefault(other.saslMechanismProperties, original.saslMechanismProperties);
this.callbackIntercept = other.callbackIntercept == null ? original.callbackIntercept : original.callbackIntercept == null ? other.callbackIntercept : other.callbackIntercept.or(original.callbackIntercept);
this.saslProtocol = getOrDefault(other.saslProtocol, original.saslProtocol);
this.webServicesProperties = getOrDefault(other.webServicesProperties, original.webServicesProperties);
sanitazeOnMutation(SET_USER_CBH);
}
private static T getOrDefault(T value, T defVal) {
return value != null ? value : defVal;
}
private static int getOrDefault(int value, int defVal) {
return value != -1 ? value : defVal;
}
// test method
Principal getPrincipal() {
return authenticationNameForwardSecurityDomain != null ? authenticationNameForwardSecurityDomain.getCurrentSecurityIdentity().getPrincipal() : principal;
}
@Deprecated
String getHost() {
return setHost;
}
@Deprecated
String getProtocol() {
return setProtocol;
}
String getSaslProtocol() {
return saslProtocol;
}
@Deprecated
int getPort() {
return setPort;
}
String getWsHttpMechanism() {
if (webServicesProperties != null) {
Object wsHttpMechanism = webServicesProperties.get("http-mechanism");
if (wsHttpMechanism != null) {
return wsHttpMechanism.toString();
}
}
return null;
}
String getWsSecurityType() {
if (webServicesProperties != null) {
Object wsSecurityType = webServicesProperties.get("ws-security-type");
if (wsSecurityType != null) {
return wsSecurityType.toString();
}
}
return null;
}
// internal actions
/**
* Determine if this SASL mechanism is supported by this configuration (not policy). Implementations must
* combine using boolean-OR operations.
*
* @param mechanismName the mech name (must not be {@code null})
* @return {@code true} if supported, {@code false} otherwise
*/
boolean saslSupportedByConfiguration(String mechanismName) {
// special case for local, quiet auth
// anonymous is only supported if the principal is anonymous. If the principal is anonymous, only anonymous or principal-less mechanisms are supported.
if (! userCallbackKinds.contains(CallbackKind.PRINCIPAL) && principal != AnonymousPrincipal.getInstance()) {
// no callback which can handle a principal.
if (! (mechanismName.equals(SaslMechanismInformation.Names.JBOSS_LOCAL_USER) || SaslMechanismInformation.doesNotUsePrincipal(mechanismName))) {
// the mechanism requires a principal.
if (getPrincipal() instanceof AnonymousPrincipal != mechanismName.equals(SaslMechanismInformation.Names.ANONYMOUS)) {
// either we have no principal & the mech requires one, or we have a principal but the mech is anonymous.
return false;
}
}
}
// if we have a credential-providing callback handler, we support any mechanism from here on out
if (userCallbackKinds.contains(CallbackKind.CREDENTIAL) || (credentialSource != null && ! credentialSource.equals(IdentityCredentials.NONE))) {
return true;
}
// mechanisms that do not need credentials are probably supported
if (SaslMechanismInformation.doesNotRequireClientCredentials(mechanismName)) {
return true;
}
// if we have a key manager factory, we definitely support IEC/ISO 9798
if (keyManagerFactory != null && SaslMechanismInformation.IEC_ISO_9798.test(mechanismName)) {
return true;
}
// otherwise, use mechanism information and our credential set
if (credentialSource != null) {
Set> types = SaslMechanismInformation.getSupportedClientCredentialTypes(mechanismName);
final CredentialSource credentials = credentialSource;
for (Class extends Credential> type : types) {
if (AlgorithmCredential.class.isAssignableFrom(type)) {
Set algorithms = SaslMechanismInformation.getSupportedClientCredentialAlgorithms(mechanismName, type);
if (algorithms.contains("*")) {
try {
if (credentials.getCredentialAcquireSupport(type, null).mayBeSupported()) {
return true;
}
} catch (IOException e) {
// no match
}
} else {
for (String algorithm : algorithms) {
try {
if (credentials.getCredentialAcquireSupport(type, algorithm).mayBeSupported()) {
return true;
}
} catch (IOException e) {
// no match
}
}
}
} else {
try {
if (credentials.getCredentialAcquireSupport(type).mayBeSupported()) {
return true;
}
} catch (IOException e) {
// no match
}
}
}
}
// no apparent way to support the mechanism
return false;
}
Principal doRewriteUser(Principal original) {
final Function principalRewriter = this.principalRewriter;
final Principal rewritten = principalRewriter == null ? original : principalRewriter.apply(original);
if (rewritten == null) {
throw log.invalidName();
}
return rewritten;
}
Principal getAuthorizationPrincipal() {
return authorizationNameForwardSecurityDomain != null ? authorizationNameForwardSecurityDomain.getCurrentSecurityIdentity().getPrincipal() : setAuthzPrincipal;
}
Supplier getProviderSupplier() {
final Supplier providerSupplier = this.providerSupplier;
return providerSupplier == null ? INSTALLED_PROVIDERS : providerSupplier;
}
SaslClientFactory getSaslClientFactory(Supplier providers) {
final Supplier supplier = saslClientFactorySupplier;
return supplier != null ? supplier.get() : new SecurityProviderSaslClientFactory(providers);
}
SecurityFactory getX509TrustManagerFactory() {
return trustManagerFactory == null ? SSLUtils.getDefaultX509TrustManagerSecurityFactory() : trustManagerFactory;
}
SecurityFactory getX509KeyManagerFactory() {
return keyManagerFactory;
}
CredentialSource getCredentialSource() {
if (authenticationCredentialsForwardSecurityDomain != null) {
return doPrivileged((PrivilegedAction) () -> authenticationCredentialsForwardSecurityDomain.getCurrentSecurityIdentity().getPrivateCredentials(), capturedAccessContext);
} else {
return credentialSource;
}
}
// assembly methods - rewrite
/**
* Create a new configuration which is the same as this configuration, but rewrites the user name using the given
* name rewriter. The name rewriter is appended to the the existing name rewrite function.
*
* @param rewriter the name rewriter
* @return the new configuration
*/
public AuthenticationConfiguration rewriteUser(NameRewriter rewriter) {
if (rewriter == null) {
return this;
}
if (this.principalRewriter == null) {
return new AuthenticationConfiguration(this, SET_PRINCIPAL_RW, rewriter.asPrincipalRewriter());
}
return new AuthenticationConfiguration(this, SET_PRINCIPAL_RW, principalRewriter.andThen(rewriter.asPrincipalRewriter()));
}
/**
* Create a new configuration which is the same as this configuration, but rewrites the user name using only
* the given name rewriter. Any name rewriters on this configuration are ignored for the new configuration.
*
* @param rewriter the name rewriter
* @return the new configuration
*/
public AuthenticationConfiguration rewriteUserOnlyWith(NameRewriter rewriter) {
if (rewriter == null) {
return this;
}
return new AuthenticationConfiguration(this, SET_PRINCIPAL_RW, rewriter.asPrincipalRewriter());
}
// assembly methods - filter
// assembly methods - configuration
/**
* Create a new configuration which is the same as this configuration, but which uses an anonymous login.
*
* @return the new configuration
*/
public AuthenticationConfiguration useAnonymous() {
return usePrincipal(AnonymousPrincipal.getInstance());
}
/**
* Create a new configuration which is the same as this configuration, but which uses the given principal to authenticate.
*
* @param principal the principal to use (must not be {@code null})
* @return the new configuration
*/
public AuthenticationConfiguration usePrincipal(NamePrincipal principal) {
return usePrincipal((Principal) principal);
}
/**
* Create a new configuration which is the same as this configuration, but which uses the given principal to authenticate.
*
* @param principal the principal to use (must not be {@code null})
* @return the new configuration
*/
public AuthenticationConfiguration usePrincipal(Principal principal) {
Assert.checkNotNullParam("principal", principal);
if (Objects.equals(this.principal, principal)) {
return this;
}
return new AuthenticationConfiguration(this, SET_PRINCIPAL, principal);
}
/**
* Create a new configuration which is the same as this configuration, but which uses the given login name to authenticate.
*
* @param name the principal to use (must not be {@code null})
* @return the new configuration
*/
public AuthenticationConfiguration useName(String name) {
Assert.checkNotNullParam("name", name);
return usePrincipal(new NamePrincipal(name));
}
/**
* Create a new configuration which is the same as this configuration, but which attempts to authorize to the given
* name after authentication. Only mechanisms which support an authorization name principal will be selected.
*
* @param name the name to use, or {@code null} to not request authorization in the new configuration
* @return the new configuration
*/
public AuthenticationConfiguration useAuthorizationName(String name) {
return useAuthorizationPrincipal(name == null ? null : new NamePrincipal(name));
}
/**
* Create a new configuration which is the same as this configuration, but which attempts to authorize to the given
* principal after authentication. Only mechanisms which support an authorization principal of the given type will
* be selected.
*
* @param principal the principal to use, or {@code null} to not request authorization in the new configuration
* @return the new configuration
*/
public AuthenticationConfiguration useAuthorizationPrincipal(Principal principal) {
if (Objects.equals(principal, setAuthzPrincipal)) {
return this;
} else {
return new AuthenticationConfiguration(this, SET_AUTHZ_PRINCIPAL, principal);
}
}
/**
* Create a new configuration which is the same as this configuration, but which uses the given credential to authenticate.
*
* @param credential the credential to authenticate
* @return the new configuration
*/
public AuthenticationConfiguration useCredential(Credential credential) {
if (credential == null) return this;
final CredentialSource credentialSource = this.credentialSource;
if (credentialSource == CredentialSource.NONE) {
return new AuthenticationConfiguration(this, SET_CRED_SOURCE, IdentityCredentials.NONE.withCredential(credential));
} else if (credentialSource instanceof IdentityCredentials) {
return new AuthenticationConfiguration(this, SET_CRED_SOURCE, ((IdentityCredentials) credentialSource).withCredential(credential));
} else {
return new AuthenticationConfiguration(this, SET_CRED_SOURCE, credentialSource.with(IdentityCredentials.NONE.withCredential(credential)));
}
}
/**
* Create a new configuration which is the same as this configuration, but which uses the given password to authenticate.
*
* @param password the password to use
* @return the new configuration
*/
public AuthenticationConfiguration usePassword(Password password) {
final CredentialSource filtered = getCredentialSource().without(PasswordCredential.class);
return password == null ? useCredentials(filtered) : useCredentials(filtered).useCredential(new PasswordCredential(password));
}
/**
* Create a new configuration which is the same as this configuration, but which uses the given password to authenticate.
*
* @param password the password to use
* @return the new configuration
*/
public AuthenticationConfiguration usePassword(char[] password) {
return usePassword(password == null ? null : ClearPassword.createRaw(ClearPassword.ALGORITHM_CLEAR, password));
}
/**
* Create a new configuration which is the same as this configuration, but which uses the given password to authenticate.
*
* @param password the password to use
* @return the new configuration
*/
public AuthenticationConfiguration usePassword(String password) {
return usePassword(password == null ? null : ClearPassword.createRaw(ClearPassword.ALGORITHM_CLEAR, password.toCharArray()));
}
/**
* Create a new configuration which is the same as this configuration, but converts the given masked password to a
* clear password and uses the clear password to authenticate.
*
* @param password the password to use
* @return the new configuration
* @throws NoSuchAlgorithmException if algorithm used to get PasswordFactory instance is invalid
* @throws InvalidKeySpecException if invalid spec is used to generate password
*/
public AuthenticationConfiguration useMaskedPassword(MaskedPassword password) throws NoSuchAlgorithmException, InvalidKeySpecException {
Assert.assertNotNull(password);
final PasswordFactory passwordFactory = PasswordFactory.getInstance(password.getAlgorithm());
final ClearPasswordSpec spec = passwordFactory.getKeySpec(password, ClearPasswordSpec.class);
final char[] clearPassword = spec.getEncodedPassword();
PasswordFactory factory = PasswordFactory.getInstance(ClearPassword.ALGORITHM_CLEAR);
Password finalPassword = factory.generatePassword(new ClearPasswordSpec(clearPassword)).castAs(ClearPassword.class);
final CredentialSource filtered = getCredentialSource().without(PasswordCredential.class);
return finalPassword == null ? useCredentials(filtered) : useCredentials(filtered).useCredential(new PasswordCredential(finalPassword));
}
/**
* Create a new configuration which is the same as this configuration, but which uses the given masked password to authenticate.
*
* @param maskedPasswordBytes the masked password bytes (must not be {@code null})
* @param algorithm the algorithm (can be {@code null}, default:"masked-MD5-DES")
* @param initialKeyMaterial the initial key material (can be {@code null}, default:"somearbitrarycrazystringthatdoesnotmatter")
* @param iterationCount the iteration count (must not be less than 1)
* @param salt the salt bytes (must not be {@code null})
* @param initializationVector the initialization vector (can be {@code null})
* @return the new configuration
* @throws NoSuchAlgorithmException if algorithm used to get PasswordFactory instance is invalid
* @throws InvalidKeySpecException if invalid spec is used to generate password
*/
public AuthenticationConfiguration useMaskedPassword(byte[] maskedPasswordBytes, String algorithm, char[] initialKeyMaterial, int iterationCount, byte[] salt, byte[] initializationVector) throws NoSuchAlgorithmException, InvalidKeySpecException {
Assert.checkMinimumParameter("iterationCount", 1, iterationCount);
Assert.assertNotNull(salt);
Assert.assertNotNull(maskedPasswordBytes);
if (algorithm == null) algorithm = MaskedPassword.ALGORITHM_MASKED_MD5_DES;
if (initialKeyMaterial == null) initialKeyMaterial = "somearbitrarycrazystringthatdoesnotmatter".toCharArray();
final MaskedPasswordSpec spec = new MaskedPasswordSpec(initialKeyMaterial, iterationCount, salt, maskedPasswordBytes, initializationVector);
PasswordFactory factory = PasswordFactory.getInstance(algorithm);
MaskedPassword password = factory.generatePassword(spec).castAs(MaskedPassword.class);
return useMaskedPassword(password);
}
/**
* Create a new configuration which is the same as this configuration, but which uses the given masked password to authenticate.
*
* @param maskedPassword the masked password, as a string (must not be {@code null})
* @param algorithm the algorithm (can be {@code null}, default:"masked-MD5-DES")
* @param initialKeyMaterial the initial key material, as a string(can be {@code null}, default:"somearbitrarycrazystringthatdoesnotmatter")
* @param iterationCount the iteration count, as an integer (must not be less than 1)
* @param salt the salt, as a string (must not be {@code null})
* @param initializationVector the initialization vector, as a string (can be {@code null})
* @return the new configuration
* @throws NoSuchAlgorithmException if algorithm used to get PasswordFactory instance is invalid
* @throws InvalidKeySpecException if invalid spec is used to generate password
*/
public AuthenticationConfiguration useMaskedPassword(String maskedPassword, String algorithm, String initialKeyMaterial, int iterationCount, String salt, String initializationVector) throws InvalidKeySpecException, NoSuchAlgorithmException {
byte[] finalMaskedPasswordBytes = maskedPassword == null ? null : CodePointIterator.ofString(maskedPassword).base64Decode().drain();
char[] finalInitialKeyMaterial = initialKeyMaterial == null ? null : initialKeyMaterial.toCharArray();
byte[] finalSalt = salt == null ? null : CodePointIterator.ofString(salt).asUtf8().drain();
byte[] finalInitializationVector = initializationVector == null ? null : CodePointIterator.ofString(initializationVector).base64Decode().drain();
return useMaskedPassword(finalMaskedPasswordBytes, algorithm, finalInitialKeyMaterial, iterationCount, finalSalt, finalInitializationVector);
}
/**
* Create a new configuration which is the same as this configuration, but which uses the given callback handler to
* acquire a password with which to authenticate, when a password-based authentication algorithm is in use.
*
* @param callbackHandler the password callback handler
* @return the new configuration
*/
public AuthenticationConfiguration useCredentialCallbackHandler(CallbackHandler callbackHandler) {
return useCallbackHandler(callbackHandler, EnumSet.of(CallbackKind.CREDENTIAL));
}
/**
* Create a new configuration which is the same as this configuration, but which uses the given callback handler
* to authenticate.
*
* Important notes: It is important to ensure that each distinct client identity uses a distinct {@code CallbackHandler}
* instance in order to avoid mis-pooling of connections, identity crossovers, and other potentially serious problems.
* It is not recommended that a {@code CallbackHandler} implement {@code equals()} and {@code hashCode()}, however if it does,
* it is important to ensure that these methods consider equality based on an authenticating identity that does not
* change between instances. In particular, a callback handler which requests user input on each usage is likely to cause
* a problem if the user name can change on each authentication request.
*
* Because {@code CallbackHandler} instances are unique per identity, it is often useful for instances to cache
* identity information, credentials, and/or other authentication-related information in order to facilitate fast
* re-authentication.
*
* @param callbackHandler the callback handler to use
* @return the new configuration
*/
public AuthenticationConfiguration useCallbackHandler(CallbackHandler callbackHandler) {
return callbackHandler == null ? this : new AuthenticationConfiguration(this, SET_USER_CBH, callbackHandler, SET_USER_CB_KINDS, EnumSet.allOf(CallbackKind.class));
}
/**
* Create a new configuration which is the same as this configuration, but which uses the given callback handler
* to authenticate.
*
* Important notes: It is important to ensure that each distinct client identity uses a distinct {@code CallbackHandler}
* instance in order to avoid mis-pooling of connections, identity crossovers, and other potentially serious problems.
* It is not recommended that a {@code CallbackHandler} implement {@code equals()} and {@code hashCode()}, however if it does,
* it is important to ensure that these methods consider equality based on an authenticating identity that does not
* change between instances. In particular, a callback handler which requests user input on each usage is likely to cause
* a problem if the user name can change on each authentication request.
*
* Because {@code CallbackHandler} instances are unique per identity, it is often useful for instances to cache
* identity information, credentials, and/or other authentication-related information in order to facilitate fast
* re-authentication.
*
* @param callbackHandler the callback handler to use
* @param callbackKinds the kinds of callbacks that the handler should use
* @return the new configuration
*/
public AuthenticationConfiguration useCallbackHandler(CallbackHandler callbackHandler, Set callbackKinds) {
return callbackHandler == null ? this : new AuthenticationConfiguration(this, SET_USER_CBH, callbackHandler, SET_USER_CB_KINDS, EnumSet.copyOf(callbackKinds));
}
/**
* Create a new configuration which is the same as this configuration, but which uses the given GSS-API credential to authenticate.
*
* @param credential the GSS-API credential to use
* @return the new configuration
*/
public AuthenticationConfiguration useGSSCredential(GSSCredential credential) {
return credential == null ? this : useCredential(new GSSKerberosCredential(credential));
}
/**
* Create a new configuration which is the same as this configuration, but which uses the given key store and alias
* to acquire the credential required for authentication.
*
* @param keyStoreEntry the key store entry to use
* @return the new configuration
*/
public AuthenticationConfiguration useKeyStoreCredential(KeyStore.Entry keyStoreEntry) {
return keyStoreEntry == null ? this : useCredentials(getCredentialSource().with(new KeyStoreCredentialSource(new FixedSecurityFactory<>(keyStoreEntry))));
}
/**
* Create a new configuration which is the same as this configuration, but which uses the given key store and alias
* to acquire the credential required for authentication.
*
* @param keyStore the key store to use
* @param alias the key store alias
* @return the new configuration
*/
public AuthenticationConfiguration useKeyStoreCredential(KeyStore keyStore, String alias) {
return keyStore == null || alias == null ? this : useCredentials(getCredentialSource().with(new KeyStoreCredentialSource(keyStore, alias, null)));
}
/**
* Create a new configuration which is the same as this configuration, but which uses the given key store and alias
* to acquire the credential required for authentication.
*
* @param keyStore the key store to use
* @param alias the key store alias
* @param protectionParameter the protection parameter to use to access the key store entry
* @return the new configuration
*/
public AuthenticationConfiguration useKeyStoreCredential(KeyStore keyStore, String alias, KeyStore.ProtectionParameter protectionParameter) {
return keyStore == null || alias == null ? this : useCredentials(getCredentialSource().with(new KeyStoreCredentialSource(keyStore, alias, protectionParameter)));
}
/**
* Create a new configuration which is the same as this configuration, but which uses the given private key and X.509
* certificate chain to authenticate.
*
* @param privateKey the client private key
* @param certificateChain the client certificate chain
* @return the new configuration
*/
public AuthenticationConfiguration useCertificateCredential(PrivateKey privateKey, X509Certificate... certificateChain) {
return certificateChain == null || certificateChain.length == 0 || privateKey == null ? this : useCertificateCredential(new X509CertificateChainPrivateCredential(privateKey, certificateChain));
}
/**
* Create a new configuration which is the same as this configuration, but which uses the given private key and X.509
* certificate chain to authenticate.
*
* @param credential the credential containing the private key and certificate chain
* @return the new configuration
*/
public AuthenticationConfiguration useCertificateCredential(X509CertificateChainPrivateCredential credential) {
return credential == null ? this : useCredential(credential);
}
/**
* Create a new configuration which is the same as this configuration, but uses credentials found at the given
* alias and credential store.
*
* @param credentialStore the credential store (must not be {@code null})
* @param alias the alias within the store (must not be {@code null})
* @return the new configuration
*/
public AuthenticationConfiguration useCredentialStoreEntry(CredentialStore credentialStore, String alias) {
Assert.checkNotNullParam("credentialStore", credentialStore);
Assert.checkNotNullParam("alias", alias);
CredentialStoreCredentialSource csCredentialSource = new CredentialStoreCredentialSource(credentialStore, alias);
return useCredentials(getCredentialSource().with(csCredentialSource));
}
/**
* Create a new configuration which is the same as this configuration, but which uses the given key manager
* to acquire the credential required for authentication.
*
* @param keyManager the key manager to use
* @return the new configuration
*/
public AuthenticationConfiguration useKeyManagerCredential(X509KeyManager keyManager) {
return new AuthenticationConfiguration(this, SET_KEY_MGR_FAC, new FixedSecurityFactory<>(keyManager));
}
/**
* Create a new configuration which is the same as this configuration, but which uses local kerberos ticket cache
* to acquire the credential required for authentication.
*
* @param mechanismOids array of oid's indicating the mechanisms over which the credential is to be acquired
* @return the new configuration
*
* @since 1.2.0
* @deprecated can be ommited - kerberos based authentication mechanism obtains credential himself
*/
@Deprecated
public AuthenticationConfiguration useLocalKerberosCredential(Oid[] mechanismOids) {
return useCredentials(getCredentialSource().with(LocalKerberosCredentialSource.builder().setMechanismOids(mechanismOids).build()));
}
/**
* Create a new configuration which is the same as this configuration, but which uses the given identity
* credentials to acquire the credential required for authentication.
*
* @param credentials the credentials to use
* @return the new configuration
*/
public AuthenticationConfiguration useCredentials(CredentialSource credentials) {
return new AuthenticationConfiguration(this, SET_CRED_SOURCE, credentials == null ? CredentialSource.NONE : credentials);
}
/**
* Create a new configuration which is the same as this configuration, but which uses the given choice if the given
* predicate evaluates to {@code true}.
*
* @param matchPredicate the predicate that should be used to determine if a choice callback type and prompt are
* relevant for the given choice
* @param choice the choice to use if the given predicate evaluates to {@code true}
* @return the new configuration
*/
public AuthenticationConfiguration useChoice(BiPredicate, String> matchPredicate, String choice) {
Assert.checkNotNullParam("matchPredicate", matchPredicate);
Assert.checkNotNullParam("choice", choice);
final Predicate callbackIntercept = this.callbackIntercept;
Predicate newIntercept = cb -> {
if (! (cb instanceof ChoiceCallback)) {
return false;
}
final ChoiceCallback choiceCallback = (ChoiceCallback) cb;
if (matchPredicate.test(choiceCallback.getClass(), choiceCallback.getPrompt())) {
final String[] choices = choiceCallback.getChoices();
final int choicesLength = choices.length;
for (int i = 0; i < choicesLength; i++) {
if (choices[i].equals(choice)) {
choiceCallback.setSelectedIndex(i);
return true;
}
}
}
return false;
};
if (callbackIntercept == null) {
return new AuthenticationConfiguration(this, SET_CALLBACK_INTERCEPT, newIntercept);
} else {
return new AuthenticationConfiguration(this, SET_CALLBACK_INTERCEPT, newIntercept.or(callbackIntercept));
}
}
/**
* Create a new configuration which is the same as this configuration, but which uses the given parameter specification.
*
* @param parameterSpec the algorithm parameter specification to use
* @return the new configuration
*/
public AuthenticationConfiguration useParameterSpec(AlgorithmParameterSpec parameterSpec) {
if (parameterSpec == null) {
return this;
}
final List specs = parameterSpecs;
if (specs.isEmpty()) {
return new AuthenticationConfiguration(this, SET_PARAM_SPECS, Collections.singletonList(parameterSpec));
} else {
ArrayList newList = new ArrayList<>();
for (AlgorithmParameterSpec spec : specs) {
if (spec.getClass() == parameterSpec.getClass()) continue;
newList.add(spec);
}
if (newList.isEmpty()) {
return new AuthenticationConfiguration(this, SET_PARAM_SPECS, Collections.singletonList(parameterSpec));
} else {
newList.add(parameterSpec);
return new AuthenticationConfiguration(this, SET_PARAM_SPECS, newList);
}
}
}
/**
* Create a new configuration which is the same as this configuration, but which uses the given trust manager
* for trust verification.
*
* @param trustManager the trust manager to use or {@code null} if the default trust manager should be used
* @return the new configuration
*/
public AuthenticationConfiguration useTrustManager(X509TrustManager trustManager) {
return trustManager == null ? new AuthenticationConfiguration(this, SET_TRUST_MGR_FAC, null) : new AuthenticationConfiguration(this, SET_TRUST_MGR_FAC, new FixedSecurityFactory<>(trustManager));
}
/**
* Create a new configuration which is the same as this configuration, but which connects to a different host name.
*
* @param hostName the host name to connect to
* @return the new configuration
* @deprecated This configuration is not supported by most providers and will be removed in a future release.
*/
@Deprecated
public AuthenticationConfiguration useHost(String hostName) {
if (hostName == null || hostName.isEmpty()) {
hostName = null;
}
if (Objects.equals(this.setHost, hostName)) {
return this;
} else {
return new AuthenticationConfiguration(this, SET_HOST, hostName);
}
}
/**
* Create a new configuration which is the same as this configuration, but which specifies a different protocol to be used for outgoing connection.
*
* @param protocol the protocol to be used for outgoing connection.
* @return the new configuration
* @deprecated This configuration is not supported by most providers and will be removed in a future release.
*/
@Deprecated
public AuthenticationConfiguration useProtocol(String protocol) {
if (protocol == null || protocol.isEmpty()) {
protocol = null;
}
if (Objects.equals(this.setProtocol, protocol)) {
return this;
} else {
return new AuthenticationConfiguration(this, SET_PROTOCOL, protocol);
}
}
/**
* Create a new configuration which is the same as this configuration, but which specifies a different protocol to be passed to the authentication mechanisms.
*
* @param saslProtocol the protocol to pass to the authentication mechanisms.
* @return the new configuration
*/
public AuthenticationConfiguration useSaslProtocol(String saslProtocol) {
if (saslProtocol == null || saslProtocol.isEmpty()) {
saslProtocol = null;
}
if (Objects.equals(this.saslProtocol, saslProtocol)) {
return this;
} else {
return new AuthenticationConfiguration(this, SET_SASL_PROTOCOL, saslProtocol);
}
}
public AuthenticationConfiguration useWebServices(Map webservicesProperties) {
final HashMap newMap = new HashMap<>();
newMap.putAll(webservicesProperties);
newMap.values().removeIf(Objects::isNull);
return new AuthenticationConfiguration(this, SET_WEBSERVICES_PROPS, optimizeMap(newMap));
}
/**
* Create a new configuration which is the same as this configuration, but which connects to a different port.
*
* @param port the port to connect to, or -1 to not override the port
* @return the new configuration
* @deprecated This configuration is not supported by most providers and will be removed in a future release.
*/
@Deprecated
public AuthenticationConfiguration usePort(int port) {
if (port < -1 || port > 65535) throw log.invalidPortNumber(port);
if (port == setPort) return this;
return new AuthenticationConfiguration(this, port);
}
/**
* Create a new configuration which is the same as this configuration, but which forwards the authentication name
* and credentials from the current identity of the given security domain.
*
* @param securityDomain the security domain
* @return the new configuration
*/
public AuthenticationConfiguration useForwardedIdentity(SecurityDomain securityDomain) {
return useForwardedAuthenticationIdentity(securityDomain).useForwardedAuthenticationCredentials(securityDomain);
}
/**
* Create a new configuration which is the same as this configuration, but which forwards the authentication name
* from the current identity of the given security domain.
*
* @param securityDomain the security domain
* @return the new configuration
*/
public AuthenticationConfiguration useForwardedAuthenticationIdentity(SecurityDomain securityDomain) {
if (Objects.equals(authenticationNameForwardSecurityDomain, securityDomain)) {
return this;
} else {
return new AuthenticationConfiguration(this, SET_ACCESS_CTXT, securityDomain != null ? getContext() : null, SET_FWD_AUTH_NAME_DOMAIN, securityDomain);
}
}
/**
* Create a new configuration which is the same as this configuration, but which forwards the authentication
* credentials from the current identity of the given security domain.
*
* @param securityDomain the security domain
* @return the new configuration
*/
public AuthenticationConfiguration useForwardedAuthenticationCredentials(SecurityDomain securityDomain) {
if (Objects.equals(authenticationCredentialsForwardSecurityDomain, securityDomain)) {
return this;
} else {
return new AuthenticationConfiguration(this, SET_ACCESS_CTXT, securityDomain != null ? getContext() : null, SET_FWD_AUTH_CRED_DOMAIN, securityDomain);
}
}
/**
* Create a new configuration which is the same as this configuration, but which forwards the authorization name
* from the current identity of the given security domain.
*
* @param securityDomain the security domain
* @return the new configuration
*/
public AuthenticationConfiguration useForwardedAuthorizationIdentity(SecurityDomain securityDomain) {
if (Objects.equals(authorizationNameForwardSecurityDomain, securityDomain)) {
return this;
} else {
return new AuthenticationConfiguration(this, SET_ACCESS_CTXT, securityDomain != null ? getContext() : null, SET_FWD_AUTHZ_NAME_DOMAIN, securityDomain);
}
}
// Providers
/**
* Use the given security provider supplier to locate security implementations.
*
* @param providerSupplier the provider supplier
* @return the new configuration
*/
public AuthenticationConfiguration useProviders(Supplier providerSupplier) {
if (Objects.equals(this.providerSupplier, providerSupplier)) {
return this;
}
return new AuthenticationConfiguration(this, SET_PROVIDER_SUPPLIER, providerSupplier);
}
/**
* Use the default provider discovery behaviour of combining service loader discovered providers with the system default
* security providers when locating security implementations.
*
* @return the new configuration
*/
public AuthenticationConfiguration useDefaultProviders() {
return useProviders(DEFAULT_PROVIDER_SUPPLIER);
}
/**
* Use security providers from the given class loader.
*
* @param classLoader the class loader to search for security providers
* @return the new configuration
*/
public AuthenticationConfiguration useProvidersFromClassLoader(ClassLoader classLoader) {
return useProviders(new ProviderServiceLoaderSupplier(classLoader));
}
// SASL Mechanisms
/**
* Use a pre-existing {@link SaslClientFactory} instead of discovery.
*
* @param saslClientFactory the pre-existing {@link SaslClientFactory} to use.
* @return the new configuration.
*/
public AuthenticationConfiguration useSaslClientFactory(final SaslClientFactory saslClientFactory) {
return useSaslClientFactory(() -> saslClientFactory);
}
/**
* Use the given sasl client factory supplier to obtain the {@link SaslClientFactory} to use.
*
* @param saslClientFactory the sasl client factory supplier to use.
* @return the new configuration.
*/
public AuthenticationConfiguration useSaslClientFactory(final Supplier saslClientFactory) {
return new AuthenticationConfiguration(this, SET_SASL_FAC_SUP, saslClientFactory);
}
/**
* Use provider based discovery to load available {@link SaslClientFactory} implementations.
*
* @return the new configuration.
*/
public AuthenticationConfiguration useSaslClientFactoryFromProviders() {
return new AuthenticationConfiguration(this, SET_SASL_FAC_SUP, null);
}
// SASL Configuration
/**
* Create a new configuration which is the same as this configuration, but which sets the properties that will be passed to
* the {@code SaslClientFactory} when the mechanism is created.
*
* Existing properties defined on this authentication context will be retained unless overridden by new properties, any
* properties resulting with a value of {@code null} will be removed.
*
* @param mechanismProperties the properties to be passed to the {@code SaslClientFactory} to create the mechanism.
* @return the new configuration.
* @deprecated use {@link #useSaslMechanismProperties(Map)}
*/
@Deprecated
public AuthenticationConfiguration useMechanismProperties(Map mechanismProperties) {
return useSaslMechanismProperties(mechanismProperties);
}
/**
* Create a new configuration which is the same as this configuration, but which sets the properties that will be passed to
* the {@code SaslClientFactory} when the mechanism is created.
*
* Existing properties defined on this authentication context will be retained unless overridden by new properties, any
* properties resulting with a value of {@code null} will be removed.
*
* @param mechanismProperties the properties to be passed to the {@code SaslClientFactory} to create the mechanism.
* @return the new configuration.
*/
public AuthenticationConfiguration useSaslMechanismProperties(Map mechanismProperties) {
return useSaslMechanismProperties(mechanismProperties, false);
}
/**
* Create a new configuration which is the same as this configuration, but which sets the properties that will be passed to
* the {@code SaslClientFactory} when the mechanism is created.
*
* If exclusive the existing properties will be discarded and replaced with the new properties otherwise existing properties
* defined on this authentication context will be retained unless overridden by new properties, any properties resulting
* with a value of {@code null} will be removed.
*
* @param mechanismProperties the properties to be passed to the {@code SaslClientFactory} to create the mechanism.
* @param exclusive should the provided properties be used exclusively or merged with the existing properties?
* @return the new configuration.
* @deprecated use {@link #useSaslMechanismProperties(Map, boolean)}
*/
@Deprecated
public AuthenticationConfiguration useMechanismProperties(Map mechanismProperties, boolean exclusive) {
return useSaslMechanismProperties(mechanismProperties, exclusive);
}
/**
* Create a new configuration which is the same as this configuration, but which sets the properties that will be passed to
* the {@code SaslClientFactory} when the mechanism is created.
*
* If exclusive the existing properties will be discarded and replaced with the new properties otherwise existing properties
* defined on this authentication context will be retained unless overridden by new properties, any properties resulting
* with a value of {@code null} will be removed.
*
* @param mechanismProperties the properties to be passed to the {@code SaslClientFactory} to create the mechanism.
* @param exclusive should the provided properties be used exclusively or merged with the existing properties?
* @return the new configuration.
*/
public AuthenticationConfiguration useSaslMechanismProperties(Map mechanismProperties, boolean exclusive) {
if (!exclusive && (mechanismProperties == null || mechanismProperties.isEmpty())) return this;
final HashMap newMap = exclusive ? new HashMap<>() : new HashMap<>(this.saslMechanismProperties);
newMap.putAll(mechanismProperties);
newMap.values().removeIf(Objects::isNull);
return new AuthenticationConfiguration(this, SET_SASL_MECH_PROPS, optimizeMap(newMap));
}
/**
* Create a new configuration which is the same as this configuration, but which sets the properties that can be used by
* WebServices client.
*
* @param webServicesProperties the properties that can be used by WS client.
* @return the new configuration.
*/
public AuthenticationConfiguration useWebServicesProperties(Map webServicesProperties) {
final HashMap newMap = new HashMap<>();
newMap.putAll(webServicesProperties);
newMap.values().removeIf(Objects::isNull);
return new AuthenticationConfiguration(this, SET_WEBSERVICES_PROPS, optimizeMap(newMap));
}
private static Map optimizeMap(Map orig) {
if (orig.isEmpty()) return Collections.emptyMap();
if (orig.size() == 1) {
final Map.Entry entry = orig.entrySet().iterator().next();
return Collections.singletonMap(entry.getKey(), entry.getValue());
}
return orig;
}
/**
* Create a new configuration which is the same as this configuration, but which uses the given kerberos security
* factory to acquire the GSS credential required for authentication.
*
* @param kerberosSecurityFactory a reference to the kerberos security factory to be use
* @return the new configuration
*/
@Deprecated
public AuthenticationConfiguration useKerberosSecurityFactory(SecurityFactory extends Credential> kerberosSecurityFactory) {
CredentialSource cs = getCredentialSource();
if (kerberosSecurityFactory != null) {
return cs != null ? new AuthenticationConfiguration(this, SET_CRED_SOURCE, cs.with(new FactoryCredentialSource(kerberosSecurityFactory))) : new AuthenticationConfiguration(this, SET_CRED_SOURCE, new FactoryCredentialSource(kerberosSecurityFactory));
}
return this;
}
/**
* Set the SASL mechanism selector for this authentication configuration.
*
* @param saslMechanismSelector the SASL mechanism selector, or {@code null} to clear the current selector
* @return the new configuration
*/
public AuthenticationConfiguration setSaslMechanismSelector(SaslMechanismSelector saslMechanismSelector) {
if (Objects.equals(this.saslMechanismSelector, saslMechanismSelector)) {
return this;
}
return new AuthenticationConfiguration(this, SET_SASL_SELECTOR, saslMechanismSelector);
}
// other
/**
* Create a new configuration which is the same as this configuration, but uses the given realm for authentication.
*
* @param realm the realm to use, or {@code null} to accept the default realm always
* @return the new configuration
*/
public AuthenticationConfiguration useRealm(String realm) {
if (Objects.equals(realm, this.setRealm)) {
return this;
} else {
return new AuthenticationConfiguration(this, SET_REALM, realm);
}
}
/**
* Create a new configuration which is the same as this configuration, but which uses the given {@link BearerTokenCredential} to authenticate.
*
* @param credential the bearer token credential to use
* @return the new configuration
*/
public AuthenticationConfiguration useBearerTokenCredential(BearerTokenCredential credential) {
return credential == null ? this : useCredentials(getCredentialSource().with(IdentityCredentials.NONE.withCredential(credential)));
}
/**
* Create a new configuration which is the same as this configuration, but which captures the caller's access
* control context to be used in authentication decisions.
*
* @return the new configuration
*/
public AuthenticationConfiguration withCapturedAccessControlContext() {
return new AuthenticationConfiguration(this, SET_ACCESS_CTXT, getContext());
}
// merging
/**
* Create a new configuration which is the same as this configuration, but which adds or replaces every item in the
* {@code other} configuration with that item, overwriting any corresponding such item in this configuration.
*
* @param other the other authentication configuration
* @return the merged authentication configuration
*/
public AuthenticationConfiguration with(AuthenticationConfiguration other) {
return new AuthenticationConfiguration(this, other);
}
/**
* Create a new configuration which is the same as this configuration, but which attempts to authorize to the
* principal from the current identity from the configured security domain.
*
* @return the new configuration
*/
public AuthenticationConfiguration captureAuthorizationIdentity() {
if (authorizationNameForwardSecurityDomain == null) {
return this;
}
return new AuthenticationConfiguration(this, SET_ACCESS_CTXT, null, SET_FWD_AUTHZ_NAME_DOMAIN, null, SET_AUTHZ_PRINCIPAL, authorizationNameForwardSecurityDomain.getCurrentSecurityIdentity().getPrincipal());
}
// client methods
CallbackHandler getUserCallbackHandler() {
return userCallbackHandler;
}
EnumSet getUserCallbackKinds() {
return userCallbackKinds;
}
private SaslClientFactory getSaslClientFactory() {
if (saslClientFactory == null) {
synchronized (this) {
if (saslClientFactory == null) {
saslClientFactory = getSaslClientFactory(getProviderSupplier());
}
}
}
return saslClientFactory;
}
SaslClient createSaslClient(URI uri, Collection serverMechanisms, UnaryOperator factoryOperator, SSLSession sslSession) throws SaslException {
SaslClientFactory saslClientFactory = factoryOperator.apply(getSaslClientFactory());
final SaslMechanismSelector selector = this.saslMechanismSelector;
serverMechanisms = (selector == null ? SaslMechanismSelector.DEFAULT : selector).apply(serverMechanisms, sslSession);
if (serverMechanisms.isEmpty()) {
return null;
}
final Principal authorizationPrincipal = getAuthorizationPrincipal();
final Predicate filter;
final String authzName;
if (authorizationPrincipal == null) {
filter = this::saslSupportedByConfiguration;
authzName = null;
} else if (authorizationPrincipal instanceof NamePrincipal) {
filter = this::saslSupportedByConfiguration;
authzName = authorizationPrincipal.getName();
} else if (authorizationPrincipal instanceof AnonymousPrincipal) {
filter = ((Predicate) this::saslSupportedByConfiguration).and("ANONYMOUS"::equals);
authzName = null;
} else {
return null;
}
Map mechanismProperties = this.saslMechanismProperties;
if (! mechanismProperties.isEmpty()) {
mechanismProperties = new HashMap<>(mechanismProperties);
// special handling for JBOSS-LOCAL-USER quiet auth... only pass it through if we have a user callback
if (! userCallbackKinds.contains(CallbackKind.PRINCIPAL) && principal != AnonymousPrincipal.getInstance()) {
mechanismProperties.remove(JBOSS_LOCAL_USER_QUIET_AUTH);
mechanismProperties.remove(JBOSS_LOCAL_USER_LEGACY_QUIET_AUTH);
}
if (! mechanismProperties.isEmpty()) {
saslClientFactory = new PropertiesSaslClientFactory(saslClientFactory, mechanismProperties);
}
}
String host = uri.getHost();
if (host != null) {
saslClientFactory = new ServerNameSaslClientFactory(saslClientFactory, host);
}
String protocol = getSaslProtocol();
if (protocol != null) {
saslClientFactory = new ProtocolSaslClientFactory(saslClientFactory, protocol);
}
if (sslSession != null) {
saslClientFactory = new SSLSaslClientFactory(() -> SSLConnection.forSession(sslSession, true), saslClientFactory);
}
saslClientFactory = new LocalPrincipalSaslClientFactory(new FilterMechanismSaslClientFactory(saslClientFactory, filter));
final SaslClientFactory finalSaslClientFactory = saslClientFactory;
saslClientFactory = WILDFLY_ELYTRON_CAPTURE_ACCESS_CONTROL_CONTEXT_PROPERTY ? doPrivileged((PrivilegedAction) () -> new PrivilegedSaslClientFactory(finalSaslClientFactory), capturedAccessContext) :
new PrivilegedSaslClientFactory(finalSaslClientFactory);
SaslClient saslClient = saslClientFactory.createSaslClient(serverMechanisms.toArray(NO_STRINGS),
authzName, uri.getScheme(), uri.getHost(), Collections.emptyMap(), createCallbackHandler());
if (log.isTraceEnabled()) {
log.tracef("Created SaslClient [%s] for mechanisms %s", saslClient, Arrays2.objectToString(serverMechanisms));
}
return saslClient;
}
CallbackHandler createCallbackHandler() {
return new ClientCallbackHandler(this);
}
// equality
/**
* Determine whether this configuration is equal to another object. Two configurations are equal if they
* apply the same items.
*
* @param obj the other object
* @return {@code true} if they are equal, {@code false} otherwise
*/
public boolean equals(final Object obj) {
return obj instanceof AuthenticationConfiguration && equals((AuthenticationConfiguration) obj);
}
/**
* Determine whether this configuration is equal to another object. Two configurations are equal if they
* apply the same items.
*
* @param other the other object
* @return {@code true} if they are equal, {@code false} otherwise
*/
public boolean equals(final AuthenticationConfiguration other) {
return hashCode() == other.hashCode()
&& Objects.equals(principal, other.principal)
&& Objects.equals(setHost, other.setHost)
&& Objects.equals(setProtocol, other.setProtocol)
&& Objects.equals(setRealm, other.setRealm)
&& Objects.equals(setAuthzPrincipal, other.setAuthzPrincipal)
&& Objects.equals(authenticationNameForwardSecurityDomain, other.authenticationNameForwardSecurityDomain)
&& Objects.equals(authenticationCredentialsForwardSecurityDomain, other.authenticationCredentialsForwardSecurityDomain)
&& Objects.equals(authorizationNameForwardSecurityDomain, other.authorizationNameForwardSecurityDomain)
&& Objects.equals(userCallbackHandler, other.userCallbackHandler)
&& Objects.equals(userCallbackKinds, other.userCallbackKinds)
&& Objects.equals(credentialSource, other.credentialSource)
&& this.setPort == other.setPort
&& Objects.equals(providerSupplier, other.providerSupplier)
&& Objects.equals(keyManagerFactory, other.keyManagerFactory)
&& Objects.equals(saslMechanismSelector, other.saslMechanismSelector)
&& Objects.equals(principalRewriter, other.principalRewriter)
&& Objects.equals(saslClientFactorySupplier, other.saslClientFactorySupplier)
&& Objects.equals(parameterSpecs, other.parameterSpecs)
&& Objects.equals(trustManagerFactory, other.trustManagerFactory)
&& Objects.equals(saslMechanismProperties, other.saslMechanismProperties)
&& Objects.equals(saslProtocol, other.saslProtocol)
&& Objects.equals(webServicesProperties, other.webServicesProperties);
}
/**
* Get the hash code of this authentication configuration.
*
* @return the hash code of this authentication configuration
*/
public int hashCode() {
int hashCode = this.hashCode;
if (hashCode == 0) {
hashCode = Objects.hash(
principal, setHost, setProtocol, setRealm, setAuthzPrincipal, authenticationNameForwardSecurityDomain,
authenticationCredentialsForwardSecurityDomain, authorizationNameForwardSecurityDomain, userCallbackHandler, credentialSource,
providerSupplier, keyManagerFactory, saslMechanismSelector, principalRewriter, saslClientFactorySupplier, parameterSpecs, trustManagerFactory,
saslMechanismProperties, saslProtocol, webServicesProperties) * 19 + setPort;
if (hashCode == 0) {
hashCode = 1;
}
this.hashCode = hashCode;
}
return hashCode;
}
// String Representation
@Override
public String toString() {
String toString = this.toString;
if (toString == null) {
StringBuilder b = new StringBuilder(64);
b.append("AuthenticationConfiguration:");
b.append("principal=").append(principal).append(',');
if (setAuthzPrincipal != null) b.append("authorization-id=").append(setAuthzPrincipal).append(',');
if (setHost != null) b.append("set-host=").append(setHost).append(',');
if (setProtocol != null) b.append("set-protocol=").append(setProtocol).append(',');
if (saslProtocol != null) b.append("sasl-protocol-name=").append(saslProtocol).append(',');
if (setPort != -1) b.append("set-port=").append(setPort).append(',');
if (setRealm != null) b.append("set-realm=").append(setRealm).append(',');
if (authenticationNameForwardSecurityDomain != null) b.append("forwarding-authentication-name,");
if (authenticationCredentialsForwardSecurityDomain != null) b.append("forwarding-authentication-credentials,");
if (authorizationNameForwardSecurityDomain != null) b.append("forwarding-authorization-name,");
if (userCallbackHandler != null) b.append("user-callback-handler=").append(userCallbackHandler).append(',');
if (! userCallbackKinds.isEmpty()) b.append("user-callback-kinds=").append(userCallbackKinds).append(',');
if (credentialSource != null && credentialSource != CredentialSource.NONE && credentialSource != IdentityCredentials.NONE) b.append("credentials-present,");
if (providerSupplier != null) b.append("providers-supplier=").append(providerSupplier).append(',');
if (keyManagerFactory != null) b.append("key-manager-factory=").append(keyManagerFactory).append(',');
if (saslMechanismSelector != null) b.append("sasl-mechanism-selector=").append(saslMechanismSelector).append(',');
if (principalRewriter != null) b.append("principal-rewriter=").append(principalRewriter).append(',');
if (saslClientFactorySupplier != null) b.append("sasl-client-factory-supplier=").append(saslClientFactorySupplier).append(',');
if (! parameterSpecs.isEmpty()) b.append("parameter-specifications=").append(parameterSpecs).append(',');
if (trustManagerFactory != null) b.append("trust-manager-factory=").append(trustManagerFactory).append(',');
if (! saslMechanismProperties.isEmpty()) b.append("mechanism-properties=").append(saslMechanismProperties).append(',');
if (webServicesProperties != null && ! webServicesProperties.isEmpty()) b.append("webservices-properties=").append(webServicesProperties).append(',');
b.setLength(b.length() - 1);
this.toString = b.toString();
return this.toString;
}
return toString;
}
//user callback sanitation
private void sanitazeOnMutation(final int what) {
switch (what) {
case SET_PRINCIPAL:
// CallbackKind.PRINCIPAL
if (this.principal != null && ! this.principal.equals(AnonymousPrincipal.getInstance())) {
this.userCallbackKinds.remove(CallbackKind.PRINCIPAL);
}
break;
case SET_CRED_SOURCE:
// CallbackKind.CREDENTIAL
if (this.credentialSource != null && ! this.credentialSource.equals(IdentityCredentials.NONE)) {
this.userCallbackKinds.remove(CallbackKind.CREDENTIAL);
}
break;
case SET_REALM:
// CallbackKind.REALM
this.userCallbackKinds.remove(CallbackKind.REALM);
break;
case SET_PARAM_SPECS:
// CallbackKind.PARAMETERS
this.userCallbackKinds.remove(CallbackKind.PARAMETERS);
break;
case SET_KEY_MGR_FAC:
// CallbackKind.PEER_CREDENTIAL
this.userCallbackKinds.remove(CallbackKind.PEER_CREDENTIAL);
break;
case SET_USER_CB_KINDS:
// SANITAZE on above content
if (this.principal != null) {
sanitazeOnMutation(SET_PRINCIPAL);
}
if (this.credentialSource != null) {
sanitazeOnMutation(SET_CRED_SOURCE);
}
if (this.setRealm != null) {
sanitazeOnMutation(SET_REALM);
}
if (this.parameterSpecs != null) {
sanitazeOnMutation(SET_PARAM_SPECS);
}
if (this.keyManagerFactory != null) {
sanitazeOnMutation(SET_KEY_MGR_FAC);
}
break;
}
}
AccessControlContext getCapturedContext() {
return capturedAccessContext;
}
// delegates for equality tests
// interfaces
static class ClientCallbackHandler implements CallbackHandler {
private final AuthenticationConfiguration config;
private final CallbackHandler userCallbackHandler;
private List trustedAuthorities;
private SSLConnection sslConnection;
ClientCallbackHandler(final AuthenticationConfiguration config) {
this.config = config;
userCallbackHandler = config.getUserCallbackHandler();
}
@SuppressWarnings("UnnecessaryContinue")
public void handle(final Callback[] callbacks) throws IOException, UnsupportedCallbackException {
final AuthenticationConfiguration config = this.config;
final Predicate callbackIntercept = config.callbackIntercept;
final ArrayList userCallbacks = new ArrayList<>(callbacks.length);
for (final Callback callback : callbacks) {
if (callbackIntercept != null && callbackIntercept.test(callback)) {
continue;
} else if (callback instanceof NameCallback) {
if (config.getUserCallbackKinds().contains(CallbackKind.PRINCIPAL)) {
userCallbacks.add(callback);
continue;
}
final NameCallback nameCallback = (NameCallback) callback;
// populate with our authentication name
final Principal principal = config.getPrincipal();
if (principal instanceof AnonymousPrincipal) {
final String defaultName = nameCallback.getDefaultName();
if (defaultName != null) {
nameCallback.setName(defaultName);
}
// otherwise set nothing; the mech can decide if that's OK or not
continue;
} else {
nameCallback.setName(config.doRewriteUser(principal).getName());
continue;
}
} else if (callback instanceof PasswordCallback) {
if (config.getUserCallbackKinds().contains(CallbackKind.CREDENTIAL)) {
userCallbacks.add(callback);
continue;
}
final PasswordCallback passwordCallback = (PasswordCallback) callback;
final CredentialSource credentials = config.getCredentialSource();
if (credentials != null) {
final TwoWayPassword password = credentials.applyToCredential(PasswordCredential.class, ClearPassword.ALGORITHM_CLEAR, c -> c.getPassword(TwoWayPassword.class));
if (password instanceof ClearPassword) {
// shortcut
passwordCallback.setPassword(((ClearPassword) password).getPassword());
continue;
} else if (password != null) try {
PasswordFactory passwordFactory = PasswordFactory.getInstance(password.getAlgorithm());
ClearPasswordSpec clearPasswordSpec = passwordFactory.getKeySpec(passwordFactory.translate(password), ClearPasswordSpec.class);
passwordCallback.setPassword(clearPasswordSpec.getEncodedPassword());
continue;
} catch (GeneralSecurityException e) {
// not supported
CallbackUtil.unsupported(passwordCallback);
continue;
}
else {
// supported but no credentials
continue;
}
} else {
// supported but no credentials
continue;
}
} else if (callback instanceof PasswordResetCallback) {
if (config.getUserCallbackKinds().contains(CallbackKind.CREDENTIAL_RESET)) {
userCallbacks.add(callback);
continue;
}
// not supported
CallbackUtil.unsupported(callback);
continue;
} else if (callback instanceof CredentialCallback) {
if (config.getUserCallbackKinds().contains(CallbackKind.CREDENTIAL)) {
userCallbacks.add(callback);
continue;
}
final CredentialCallback credentialCallback = (CredentialCallback) callback;
// special handling for X.509 when a key manager factory is set
final SecurityFactory keyManagerFactory = config.getX509KeyManagerFactory();
if (keyManagerFactory != null) {
final String allowedAlgorithm = credentialCallback.getAlgorithm();
if (allowedAlgorithm != null && credentialCallback.isCredentialTypeSupported(X509CertificateChainPrivateCredential.class, allowedAlgorithm)) {
final X509KeyManager keyManager;
try {
keyManager = keyManagerFactory.create();
} catch (GeneralSecurityException e) {
throw log.unableToCreateKeyManager(e);
}
Principal[] acceptableIssuers;
if (trustedAuthorities != null) {
List issuers = new ArrayList();
for (TrustedAuthority trustedAuthority : trustedAuthorities) {
if (trustedAuthority instanceof TrustedAuthority.CertificateTrustedAuthority) {
final X509Certificate authorityCertificate = ((TrustedAuthority.CertificateTrustedAuthority) trustedAuthority).getIdentifier();
issuers.add(authorityCertificate.getSubjectX500Principal());
} else if (trustedAuthority instanceof TrustedAuthority.NameTrustedAuthority) {
final String authorityName = ((TrustedAuthority.NameTrustedAuthority) trustedAuthority).getIdentifier();
issuers.add(new X500Principal(authorityName));
}
}
acceptableIssuers = issuers.toArray(NO_PRINCIPALS);
} else {
acceptableIssuers = null;
}
final String alias = keyManager.chooseClientAlias(new String[] { allowedAlgorithm }, acceptableIssuers, null);
if (alias != null) {
final X509Certificate[] certificateChain = keyManager.getCertificateChain(alias);
final PrivateKey privateKey = keyManager.getPrivateKey(alias);
credentialCallback.setCredential(new X509CertificateChainPrivateCredential(privateKey, certificateChain));
continue;
}
// otherwise fall out to normal handling
}
}
// normal handling
final Credential credential = config.getCredentialSource().getCredential(credentialCallback.getCredentialType(), credentialCallback.getAlgorithm(), credentialCallback.getParameterSpec());
if (credential != null && credentialCallback.isCredentialSupported(credential)) {
credentialCallback.setCredential(credential);
continue;
} else {
// supported but no credentials
continue;
}
} else if (callback instanceof RealmChoiceCallback) {
if (config.getUserCallbackKinds().contains(CallbackKind.REALM)) {
userCallbacks.add(callback);
continue;
}
final RealmChoiceCallback realmChoiceCallback = (RealmChoiceCallback) callback;
// find our realm
final String realm = config.setRealm;
if (realm == null) {
realmChoiceCallback.setSelectedIndex(realmChoiceCallback.getDefaultChoice());
continue;
} else {
String[] choices = realmChoiceCallback.getChoices();
for (int i = 0; i < choices.length; i++) {
if (realm.equals(choices[i])) {
realmChoiceCallback.setSelectedIndex(i);
break;
}
}
// no choice matches, so just fall out and choose nothing
continue;
}
} else if (callback instanceof RealmCallback) {
if (config.getUserCallbackKinds().contains(CallbackKind.REALM)) {
userCallbacks.add(callback);
continue;
}
RealmCallback realmCallback = (RealmCallback) callback;
final String realm = config.setRealm;
realmCallback.setText(realm != null ? realm : realmCallback.getDefaultText());
continue;
} else if (callback instanceof ParameterCallback) {
if (config.getUserCallbackKinds().contains(CallbackKind.PARAMETERS)) {
userCallbacks.add(callback);
continue;
}
ParameterCallback parameterCallback = (ParameterCallback) callback;
if (parameterCallback.getParameterSpec() == null) {
for (AlgorithmParameterSpec parameterSpec : config.parameterSpecs) {
if (parameterCallback.isParameterSupported(parameterSpec)) {
parameterCallback.setParameterSpec(parameterSpec);
break; // inner loop break
}
}
}
continue;
} else if (callback instanceof SSLCallback) {
if (config.getUserCallbackKinds().contains(CallbackKind.SSL)) {
userCallbacks.add(callback);
continue;
}
SSLCallback sslCallback = (SSLCallback) callback;
this.sslConnection = sslCallback.getSslConnection();
continue;
} else if (callback instanceof ChannelBindingCallback) {
if (config.getUserCallbackKinds().contains(CallbackKind.CHANNEL_BINDING)) {
userCallbacks.add(callback);
continue;
}
final SSLConnection sslConnection = this.sslConnection;
if (sslConnection != null) {
sslConnection.handleChannelBindingCallback((ChannelBindingCallback) callback);
}
continue;
} else if (callback instanceof ChoiceCallback) { // Must come AFTER RealmChoiceCallback
if (config.getUserCallbackKinds().contains(CallbackKind.CHOICE)) {
userCallbacks.add(callback);
continue;
}
final ChoiceCallback choiceCallback = (ChoiceCallback) callback;
choiceCallback.setSelectedIndex(choiceCallback.getDefaultChoice());
continue;
} else if (callback instanceof TrustedAuthoritiesCallback) {
if (config.getUserCallbackKinds().contains(CallbackKind.SERVER_TRUSTED_AUTHORITIES)) {
userCallbacks.add(callback);
continue;
}
final TrustedAuthoritiesCallback trustedAuthoritiesCallback = (TrustedAuthoritiesCallback) callback;
final List trustedAuthoritiesHolder = trustedAuthoritiesCallback.getTrustedAuthorities();
if (trustedAuthoritiesHolder != null) {
if (trustedAuthorities == null) {
trustedAuthorities = new ArrayList<>(trustedAuthoritiesHolder);
} else {
final List authorities = new ArrayList<>(trustedAuthoritiesHolder);
authorities.removeIf(trustedAuthorities::contains);
trustedAuthorities.addAll(authorities);
}
}
continue;
} else if (callback instanceof EvidenceVerifyCallback) {
if (config.getUserCallbackKinds().contains(CallbackKind.PEER_CREDENTIAL)) {
userCallbacks.add(callback);
continue;
}
final EvidenceVerifyCallback evidenceVerifyCallback = (EvidenceVerifyCallback) callback;
// special handling for X.509
final SecurityFactory trustManagerFactory = config.getX509TrustManagerFactory();
if (trustManagerFactory != null) {
final X509PeerCertificateChainEvidence peerCertificateChainEvidence = evidenceVerifyCallback.getEvidence(X509PeerCertificateChainEvidence.class);
if (peerCertificateChainEvidence != null) {
X509TrustManager trustManager;
try {
trustManager = trustManagerFactory.create();
} catch (GeneralSecurityException e) {
throw log.unableToCreateTrustManager(e);
}
try {
trustManager.checkServerTrusted(peerCertificateChainEvidence.getPeerCertificateChain(), peerCertificateChainEvidence.getAlgorithm());
evidenceVerifyCallback.setVerified(true);
} catch (CertificateException e) {
}
continue;
}
}
continue;
} else if (callback instanceof TextOutputCallback) {
if (config.getUserCallbackKinds().contains(CallbackKind.GENERAL_OUTPUT)) {
userCallbacks.add(callback);
continue;
}
// ignore
continue;
} else if (callback instanceof TextInputCallback) { // must come after RealmCallback
if (config.getUserCallbackKinds().contains(CallbackKind.GENERAL_INPUT)) {
userCallbacks.add(callback);
continue;
}
// always choose the default
final TextInputCallback inputCallback = (TextInputCallback) callback;
final String text = inputCallback.getText();
if (text == null) {
final String defaultText = inputCallback.getDefaultText();
if (defaultText != null) {
inputCallback.setText(defaultText);
} else {
CallbackUtil.unsupported(callback);
continue;
}
}
continue;
} else if (userCallbackHandler != null) {
userCallbacks.add(callback);
} else {
CallbackUtil.unsupported(callback);
continue;
}
}
if (! userCallbacks.isEmpty()) {
// pass on to the user callback handler
assert userCallbackHandler != null; // otherwise userCallbacks would be empty
final Callback[] userCallbackArray = userCallbacks.toArray(NO_CALLBACKS);
userCallbackHandler.handle(userCallbackArray);
}
}
}
}