blob: 77dedf84eba78be3150fe4d79fd93c23e9d0ca50 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.ignite.ssl;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.atomic.AtomicReference;
import javax.cache.configuration.Factory;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.TrustManager;
import org.apache.ignite.IgniteException;
import org.apache.ignite.internal.util.typedef.internal.A;
/**
* Represents abstract implementation of SSL Context Factory that caches the result of the first successful
* attempt to create an {@link SSLContext} and always returns it as a result of further invocations of the
* {@link AbstractSslContextFactory#create()}} method.
*/
public abstract class AbstractSslContextFactory implements Factory<SSLContext> {
/** */
private static final long serialVersionUID = 0L;
/** Default SSL protocol. */
public static final String DFLT_SSL_PROTOCOL = "TLS";
/** SSL protocol. */
protected String proto = DFLT_SSL_PROTOCOL;
/** Enabled cipher suites. */
protected String[] cipherSuites;
/** Enabled protocols. */
protected String[] protocols;
/** Cached instance of an {@link SSLContext}. */
protected final AtomicReference<SSLContext> sslCtx = new AtomicReference<>();
/**
* Gets protocol for secure transport.
*
* @return SSL protocol name.
*/
public String getProtocol() {
return proto;
}
/**
* Sets protocol for secure transport. If not specified, {@link #DFLT_SSL_PROTOCOL} will be used.
*
* @param proto SSL protocol name.
*/
public void setProtocol(String proto) {
A.notNull(proto, "proto");
this.proto = proto;
}
/**
* Sets enabled cipher suites.
*
* @param cipherSuites enabled cipher suites.
*/
public void setCipherSuites(String... cipherSuites) {
this.cipherSuites = cipherSuites;
}
/**
* Gets enabled cipher suites.
*
* @return enabled cipher suites
*/
public String[] getCipherSuites() {
return cipherSuites;
}
/**
* Gets enabled protocols.
*
* @return Enabled protocols.
*/
public String[] getProtocols() {
return protocols;
}
/**
* Sets enabled protocols.
*
* @param protocols Enabled protocols.
*/
public void setProtocols(String... protocols) {
this.protocols = protocols;
}
/**
* Creates SSL context based on factory settings.
*
* @return Initialized SSL context.
* @throws SSLException If SSL context could not be created.
*/
private SSLContext createSslContext() throws SSLException {
checkParameters();
KeyManager[] keyMgrs = createKeyManagers();
TrustManager[] trustMgrs = createTrustManagers();
try {
SSLContext ctx = SSLContext.getInstance(proto);
if (cipherSuites != null || protocols != null) {
SSLParameters sslParameters = new SSLParameters();
if (cipherSuites != null)
sslParameters.setCipherSuites(cipherSuites);
if (protocols != null)
sslParameters.setProtocols(protocols);
ctx = new SSLContextWrapper(ctx, sslParameters);
}
ctx.init(keyMgrs, trustMgrs, null);
return ctx;
}
catch (NoSuchAlgorithmException e) {
throw new SSLException("Unsupported SSL protocol: " + proto, e);
}
catch (KeyManagementException e) {
throw new SSLException("Failed to initialized SSL context.", e);
}
}
/**
* @param param Value.
* @param name Name.
* @throws SSLException If {@code null}.
*/
protected void checkNullParameter(Object param, String name) throws SSLException {
if (param == null)
throw new SSLException("Failed to initialize SSL context (parameter cannot be null): " + name);
}
/**
* Checks that all required parameters are set.
*
* @throws SSLException If any of required parameters is missing.
*/
protected abstract void checkParameters() throws SSLException;
/**
* @return Created Key Managers.
* @throws SSLException If Key Managers could not be created.
*/
protected abstract KeyManager[] createKeyManagers() throws SSLException;
/**
* @return Created Trust Managers.
* @throws SSLException If Trust Managers could not be created.
*/
protected abstract TrustManager[] createTrustManagers() throws SSLException;
/** {@inheritDoc} */
@Override public SSLContext create() {
SSLContext ctx = sslCtx.get();
if (ctx == null) {
try {
ctx = createSslContext();
if (!sslCtx.compareAndSet(null, ctx))
ctx = sslCtx.get();
}
catch (SSLException e) {
throw new IgniteException(e);
}
}
return ctx;
}
}