001/**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.camel.util.jsse;
018
019import java.security.GeneralSecurityException;
020import java.util.Collections;
021import java.util.LinkedList;
022import java.util.List;
023
024import javax.net.ssl.SSLContext;
025import javax.net.ssl.SSLEngine;
026import javax.net.ssl.SSLServerSocket;
027import javax.net.ssl.SSLSocketFactory;
028
029import org.apache.camel.RuntimeCamelException;
030import org.slf4j.Logger;
031import org.slf4j.LoggerFactory;
032
033public class SSLContextServerParameters extends BaseSSLContextParameters {
034    
035    private static final Logger LOG = LoggerFactory.getLogger(SSLContextServerParameters.class);
036
037    /**
038     * The optional configuration options for server-side client-authentication requirements.
039     */
040    protected String clientAuthentication;
041    
042    /**
043     * @see #setClientAuthentication(String)
044     */
045    public String getClientAuthentication() {
046        return clientAuthentication;
047    }
048
049    /**
050     * Sets the configuration options for server-side client-authentication requirements.
051     * The value must be one of NONE, WANT, REQUIRE as defined in {@link ClientAuthentication}.
052     * 
053     * @param value the desired configuration options or {@code null} to use the defaults
054     */
055    public void setClientAuthentication(String value) {
056        this.clientAuthentication = value;
057    }
058    
059    @Override
060    protected boolean getAllowPassthrough() {
061        return true;
062    }
063    
064    @Override
065    protected void configureSSLContext(SSLContext context) throws GeneralSecurityException {
066        LOG.trace("Configuring server-side SSLContext parameters on SSLContext [{}]...", context);
067        if (this.getSessionTimeout() != null) {
068            LOG.debug("Configuring server-side SSLContext session timeout on SSLContext [{}] to [{}].", context, this.getSessionTimeout());
069            this.configureSessionContext(context.getServerSessionContext(), this.getSessionTimeout());
070        }
071        LOG.trace("Configured server-side SSLContext parameters on SSLContext [{}].", context);   
072    }
073
074    /**
075     * {@inheritDoc}
076     * <p/>
077     * This implementation allows for configuration of the need and want settings
078     * for client authentication, but ignores the enabled cipher suites
079     * and protocols as they are not client and server side specific in an
080     * {@code SSLEngine}. Consequently, overriding them here would be a bit odd
081     * as the server side specific configuration shouldn't really override a
082     * shared client/server configuration option.
083     */
084    @Override
085    protected List<Configurer<SSLEngine>> getSSLEngineConfigurers(SSLContext context) {
086        // NOTE: if the super class gets additional shared configuration options beyond
087        // cipher suites and protocols, this method needs to address that.
088        // As is, we do NOT pass the configurers along for those two settings.
089        
090        List<Configurer<SSLEngine>> sslEngineConfigurers = new LinkedList<>();
091        
092        if (this.getClientAuthentication() != null) { 
093            
094            final ClientAuthentication clientAuthValue = 
095                ClientAuthentication.valueOf(this.parsePropertyValue(this.getClientAuthentication()));
096        
097            Configurer<SSLEngine> sslEngineConfigurer = new Configurer<SSLEngine>() {
098                @Override
099                public SSLEngine configure(SSLEngine engine) {
100                    LOG.trace("Configuring client-auth on SSLEngine [{}] to [{}].", engine, clientAuthValue);
101                    switch (clientAuthValue) {
102                    case NONE:
103                        engine.setWantClientAuth(false);
104                        engine.setNeedClientAuth(false);
105                        break;
106                    case WANT:
107                        engine.setWantClientAuth(true);
108                        break;
109                    case REQUIRE:
110                        engine.setNeedClientAuth(true);
111                        break;
112                    default:
113                        throw new RuntimeCamelException("Unknown ClientAuthentication value: " + clientAuthValue);
114                    }
115                    
116                    return engine;
117                }
118            };
119            
120            sslEngineConfigurers.add(sslEngineConfigurer);
121        }
122        
123        return sslEngineConfigurers;
124    }
125    
126    @Override
127    protected List<Configurer<SSLServerSocket>> getSSLServerSocketFactorySSLServerSocketConfigurers(SSLContext context) {
128        List<Configurer<SSLServerSocket>> sslServerSocketConfigurers = 
129            super.getSSLServerSocketFactorySSLServerSocketConfigurers(context);
130        
131        if (this.getClientAuthentication() != null) {
132            
133            final ClientAuthentication clientAuthValue =
134                ClientAuthentication.valueOf(this.parsePropertyValue(this.getClientAuthentication()));
135        
136            Configurer<SSLServerSocket> sslServerSocketConfigurer = new Configurer<SSLServerSocket>() {
137                @Override
138                public SSLServerSocket configure(SSLServerSocket socket) {
139                    LOG.trace("Configuring client-auth on SSLServerSocket [{}] to [{}].", socket, clientAuthValue);
140                    switch (clientAuthValue) {
141                    case NONE:
142                        socket.setWantClientAuth(false);
143                        socket.setNeedClientAuth(false);
144                        break;
145                    case WANT:
146                        socket.setWantClientAuth(true);
147                        break;
148                    case REQUIRE:
149                        socket.setNeedClientAuth(true);
150                        break;
151                    default:
152                        throw new RuntimeCamelException("Unknown ClientAuthentication value: " + clientAuthValue);
153                    }
154                    
155                    return socket;
156                }
157            };
158            
159            sslServerSocketConfigurers.add(sslServerSocketConfigurer);
160        }
161
162        return sslServerSocketConfigurers;
163    }
164
165    /**
166     * This class has no bearing on {@code SSLSocketFactory} instances and therefore provides no
167     * configurers for that purpose.
168     */
169    @Override
170    protected List<Configurer<SSLSocketFactory>> getSSLSocketFactoryConfigurers(SSLContext context) {
171        return Collections.emptyList();
172    }
173
174    @Override
175    public String toString() {
176        StringBuilder builder = new StringBuilder();
177        builder.append("SSLContextServerParameters[clientAuthentication=");
178        builder.append(clientAuthentication);
179        builder.append(", getCipherSuites()=");
180        builder.append(getCipherSuites());
181        builder.append(", getCipherSuitesFilter()=");
182        builder.append(getCipherSuitesFilter());
183        builder.append(", getSecureSocketProtocols()=");
184        builder.append(getSecureSocketProtocols());
185        builder.append(", getSecureSocketProtocolsFilter()=");
186        builder.append(getSecureSocketProtocolsFilter());
187        builder.append(", getSessionTimeout()=");
188        builder.append(getSessionTimeout());
189        builder.append("]");
190        return builder.toString();
191    }
192}