001/*
002 * The MIT License
003 * Copyright (c) 2012 Microsoft Corporation
004 *
005 * Permission is hereby granted, free of charge, to any person obtaining a copy
006 * of this software and associated documentation files (the "Software"), to deal
007 * in the Software without restriction, including without limitation the rights
008 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
009 * copies of the Software, and to permit persons to whom the Software is
010 * furnished to do so, subject to the following conditions:
011 *
012 * The above copyright notice and this permission notice shall be included in
013 * all copies or substantial portions of the Software.
014 *
015 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
016 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
017 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
018 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
019 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
020 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
021 * THE SOFTWARE.
022 */
023
024package microsoft.exchange.webservices.data.core;
025
026import org.apache.http.conn.ssl.DefaultHostnameVerifier;
027import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
028import org.apache.http.ssl.SSLContexts;
029
030import javax.net.ssl.HostnameVerifier;
031import javax.net.ssl.SSLContext;
032import javax.net.ssl.TrustManager;
033
034import java.security.GeneralSecurityException;
035
036/**
037 * <p>
038 * EwsSSLProtocolSocketFactory can be used to create SSL {@link java.net.Socket}s
039 * that accept self-signed certificates.
040 * </p>
041 * <p>
042 * This socket factory SHOULD NOT be used for productive systems
043 * due to security reasons, unless it is a conscious decision and
044 * you are perfectly aware of security implications of accepting
045 * self-signed certificates
046 * </p>
047 * Example of using custom protocol socket factory for a specific host:
048 * <pre>
049 *     Protocol easyhttps = new Protocol("https", new EasySSLProtocolSocketFactory(), 443);
050 *
051 *     URI uri = new URI("https://localhost/", true);
052 *     // use relative url only
053 *     GetMethod httpget = new GetMethod(uri.getPathQuery());
054 *     HostConfiguration hc = new HostConfiguration();
055 *     hc.setHost(uri.getHost(), uri.getPort(), easyhttps);
056 *     HttpClient client = new HttpClient();
057 *     client.executeMethod(hc, httpget);
058 *     </pre>
059 * </p>
060 * <p>
061 * Example of using custom protocol socket factory per default instead of the standard one:
062 * <pre>
063 *     Protocol easyhttps = new Protocol("https", new EasySSLProtocolSocketFactory(), 443);
064 *     Protocol.registerProtocol("https", easyhttps);
065 *
066 *     HttpClient client = new HttpClient();
067 *     GetMethod httpget = new GetMethod("https://localhost/");
068 *     client.executeMethod(httpget);
069 *     </pre>
070 * </p>
071 *
072 * <p>
073 * DISCLAIMER: HttpClient developers DO NOT actively support this component.
074 * The component is provided as a reference material, which may be inappropriate
075 * for use without additional customization.
076 * </p>
077 */
078
079public class EwsSSLProtocolSocketFactory extends SSLConnectionSocketFactory {
080
081  /**
082   * Default hostname verifier.
083   */
084  private static final HostnameVerifier DEFAULT_HOSTNAME_VERIFIER = new DefaultHostnameVerifier();
085
086
087  /**
088   * The SSL Context.
089   */
090  private final SSLContext sslcontext;
091
092
093  /**
094   * Constructor for EasySSLProtocolSocketFactory.
095   *
096   * @param context          SSL context
097   * @param hostnameVerifier hostname verifier
098   */
099  public EwsSSLProtocolSocketFactory(
100    SSLContext context, HostnameVerifier hostnameVerifier
101  ) {
102    super(context, hostnameVerifier);
103    this.sslcontext = context;
104  }
105
106
107  /**
108   * Create and configure SSL protocol socket factory using default hostname verifier.
109   * {@link EwsSSLProtocolSocketFactory#DEFAULT_HOSTNAME_VERIFIER}
110   *
111   * @param trustManager trust manager
112   * @return socket factory for SSL protocol
113   * @throws GeneralSecurityException on security error
114   */
115  public static EwsSSLProtocolSocketFactory build(TrustManager trustManager)
116    throws GeneralSecurityException {
117    return build(trustManager, DEFAULT_HOSTNAME_VERIFIER);
118  }
119
120  /**
121   * Create and configure SSL protocol socket factory using trust manager and hostname verifier.
122   *
123   * @param trustManager trust manager
124   * @param hostnameVerifier hostname verifier
125   * @return socket factory for SSL protocol
126   * @throws GeneralSecurityException on security error
127   */
128  public static EwsSSLProtocolSocketFactory build(
129    TrustManager trustManager, HostnameVerifier hostnameVerifier
130  ) throws GeneralSecurityException {
131    SSLContext sslContext = createSslContext(trustManager);
132    return new EwsSSLProtocolSocketFactory(sslContext, hostnameVerifier);
133  }
134
135  /**
136   * Create SSL context and initialize it using specific trust manager.
137   *
138   * @param trustManager trust manager
139   * @return initialized SSL context
140   * @throws GeneralSecurityException on security error
141   */
142  public static SSLContext createSslContext(TrustManager trustManager)
143    throws GeneralSecurityException {
144    EwsX509TrustManager x509TrustManager = new EwsX509TrustManager(null, trustManager);
145    SSLContext sslContext = SSLContexts.createDefault();
146    sslContext.init(
147      null,
148      new TrustManager[] { x509TrustManager },
149      null
150    );
151    return sslContext;
152  }
153
154
155  /**
156   * @return SSL context
157   */
158  public SSLContext getContext() {
159    return sslcontext;
160  }
161
162  public boolean equals(Object obj) {
163    return ((obj != null) && obj.getClass().equals(EwsSSLProtocolSocketFactory.class));
164  }
165
166  public int hashCode() {
167    return EwsSSLProtocolSocketFactory.class.hashCode();
168  }
169
170}