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     */
017    package org.apache.camel.util.jsse;
018    
019    import java.security.GeneralSecurityException;
020    import java.util.Collections;
021    import java.util.LinkedList;
022    import java.util.List;
023    
024    import javax.net.ssl.SSLContext;
025    import javax.net.ssl.SSLEngine;
026    import javax.net.ssl.SSLServerSocket;
027    import javax.net.ssl.SSLSocketFactory;
028    
029    import org.apache.camel.RuntimeCamelException;
030    import org.slf4j.Logger;
031    import org.slf4j.LoggerFactory;
032    
033    public 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<Configurer<SSLEngine>>();
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(", getContext()=");
190            builder.append(getCamelContext());
191            builder.append("]");
192            return builder.toString();
193        }
194    }