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 * <p>
048 * Example of using custom protocol socket factory for a specific host:
049 * </p>
050 * <pre>
051 *     Protocol easyhttps = new Protocol("https", new EasySSLProtocolSocketFactory(), 443);
052 *
053 *     URI uri = new URI("https://localhost/", true);
054 *     // use relative url only
055 *     GetMethod httpget = new GetMethod(uri.getPathQuery());
056 *     HostConfiguration hc = new HostConfiguration();
057 *     hc.setHost(uri.getHost(), uri.getPort(), easyhttps);
058 *     HttpClient client = new HttpClient();
059 *     client.executeMethod(hc, httpget);
060 * </pre>
061 * <p>
062 * Example of using custom protocol socket factory per default instead of the standard one:
063 * </p>
064 * <pre>
065 *     Protocol easyhttps = new Protocol("https", new EasySSLProtocolSocketFactory(), 443);
066 *     Protocol.registerProtocol("https", easyhttps);
067 *
068 *     HttpClient client = new HttpClient();
069 *     GetMethod httpget = new GetMethod("https://localhost/");
070 *     client.executeMethod(httpget);
071 * </pre>
072 *
073 * <p>
074 * DISCLAIMER: HttpClient developers DO NOT actively support this component.
075 * The component is provided as a reference material, which may be inappropriate
076 * for use without additional customization.
077 * </p>
078 */
079
080public class EwsSSLProtocolSocketFactory extends SSLConnectionSocketFactory {
081
082  /**
083   * Default hostname verifier.
084   */
085  private static final HostnameVerifier DEFAULT_HOSTNAME_VERIFIER = new DefaultHostnameVerifier();
086
087
088  /**
089   * The SSL Context.
090   */
091  private final SSLContext sslcontext;
092
093
094  /**
095   * Constructor for EasySSLProtocolSocketFactory.
096   *
097   * @param context          SSL context
098   * @param hostnameVerifier hostname verifier
099   */
100  public EwsSSLProtocolSocketFactory(
101    SSLContext context, HostnameVerifier hostnameVerifier
102  ) {
103    super(context, hostnameVerifier);
104    this.sslcontext = context;
105  }
106
107
108  /**
109   * Create and configure SSL protocol socket factory using default hostname verifier.
110   * {@link EwsSSLProtocolSocketFactory#DEFAULT_HOSTNAME_VERIFIER}
111   *
112   * @param trustManager trust manager
113   * @return socket factory for SSL protocol
114   * @throws GeneralSecurityException on security error
115   */
116  public static EwsSSLProtocolSocketFactory build(TrustManager trustManager)
117    throws GeneralSecurityException {
118    return build(trustManager, DEFAULT_HOSTNAME_VERIFIER);
119  }
120
121  /**
122   * Create and configure SSL protocol socket factory using trust manager and hostname verifier.
123   *
124   * @param trustManager trust manager
125   * @param hostnameVerifier hostname verifier
126   * @return socket factory for SSL protocol
127   * @throws GeneralSecurityException on security error
128   */
129  public static EwsSSLProtocolSocketFactory build(
130    TrustManager trustManager, HostnameVerifier hostnameVerifier
131  ) throws GeneralSecurityException {
132    SSLContext sslContext = createSslContext(trustManager);
133    return new EwsSSLProtocolSocketFactory(sslContext, hostnameVerifier);
134  }
135
136  /**
137   * Create SSL context and initialize it using specific trust manager.
138   *
139   * @param trustManager trust manager
140   * @return initialized SSL context
141   * @throws GeneralSecurityException on security error
142   */
143  public static SSLContext createSslContext(TrustManager trustManager)
144    throws GeneralSecurityException {
145    EwsX509TrustManager x509TrustManager = new EwsX509TrustManager(null, trustManager);
146    SSLContext sslContext = SSLContexts.createDefault();
147    sslContext.init(
148      null,
149      new TrustManager[] { x509TrustManager },
150      null
151    );
152    return sslContext;
153  }
154
155
156  /**
157   * @return SSL context
158   */
159  public SSLContext getContext() {
160    return sslcontext;
161  }
162
163  public boolean equals(Object obj) {
164    return ((obj != null) && obj.getClass().equals(EwsSSLProtocolSocketFactory.class));
165  }
166
167  public int hashCode() {
168    return EwsSSLProtocolSocketFactory.class.hashCode();
169  }
170
171}