Package net.jini.jeri.ssl

Source Code of net.jini.jeri.ssl.HttpsServerEndpoint$HttpsServerEndpointImpl$HttpsServerConnection

/*
* 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 net.jini.jeri.ssl;

import com.sun.jini.jeri.internal.http.ConnectionTimer;
import com.sun.jini.jeri.internal.http.HttpServerConnection;
import com.sun.jini.jeri.internal.http.HttpServerManager;
import com.sun.jini.jeri.internal.http.HttpSettings;
import com.sun.jini.logging.Levels;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.AccessControlContext;
import java.security.Principal;
import java.security.PrivilegedAction;
import java.security.SecureRandom;
import java.security.cert.CertPath;
import java.security.cert.CertificateFactory;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.ServerSocketFactory;
import javax.net.SocketFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import javax.security.auth.Subject;
import javax.security.auth.x500.X500Principal;
import javax.security.auth.x500.X500PrivateCredential;
import net.jini.core.constraint.ClientAuthentication;
import net.jini.core.constraint.ClientMaxPrincipal;
import net.jini.core.constraint.ClientMaxPrincipalType;
import net.jini.core.constraint.ClientMinPrincipal;
import net.jini.core.constraint.ClientMinPrincipalType;
import net.jini.core.constraint.Confidentiality;
import net.jini.core.constraint.ConnectionAbsoluteTime;
import net.jini.core.constraint.ConnectionRelativeTime;
import net.jini.core.constraint.ConstraintAlternatives;
import net.jini.core.constraint.Delegation;
import net.jini.core.constraint.DelegationAbsoluteTime;
import net.jini.core.constraint.DelegationRelativeTime;
import net.jini.core.constraint.Integrity;
import net.jini.core.constraint.InvocationConstraints;
import net.jini.core.constraint.ServerAuthentication;
import net.jini.core.constraint.ServerMinPrincipal;
import net.jini.io.UnsupportedConstraintException;
import net.jini.io.context.AcknowledgmentSource;
import net.jini.io.context.ClientHost;
import net.jini.io.context.ClientSubject;
import net.jini.jeri.BasicJeriExporter;
import net.jini.jeri.Endpoint;
import net.jini.jeri.InboundRequest;
import net.jini.jeri.RequestDispatcher;
import net.jini.jeri.ServerEndpoint.ListenEndpoint;
import net.jini.jeri.ServerEndpoint.ListenHandle;
import net.jini.jeri.ServerEndpoint;
import net.jini.jeri.connection.InboundRequestHandle;
import net.jini.jeri.connection.ServerConnection;
import net.jini.jeri.connection.ServerConnectionManager;
import net.jini.security.AuthenticationPermission;
import net.jini.security.SecurityContext;

/**
* An implementation of {@link ServerEndpoint} that uses HTTPS (HTTP over
* TLS/SSL) to support invocation constraints for communication through
* firewalls. <p>
*
* Instances of this class are intended to be created for use with the {@link
* BasicJeriExporter} class. Calls to {@link #enumerateListenEndpoints
* enumerateListenEndpoints} return instances of {@link HttpsEndpoint}. <p>
*
* This class supports at least the following constraints, possibly limited by
* the available cipher suites: <p>
*
* <ul>
* <li> {@link ClientAuthentication}
* <li> {@link ClientMaxPrincipal}, when it contains an {@link X500Principal}
* <li> {@link ClientMaxPrincipalType}, when it contains
<code>X500Principal</code>
* <li> {@link ClientMinPrincipal}, when it contains a single
<code>X500Principal</code> only
* <li> {@link ClientMinPrincipalType}, when it contains
<code>X500Principal</code> only
* <li> {@link Confidentiality}
* <li> {@link ConfidentialityStrength}, a provider-specific constraint for
*  specifying weak or strong confidentiality
* <li> {@link ConnectionAbsoluteTime}, trivially, since this only takes effect
*  on the client side
* <li> {@link ConnectionRelativeTime}, trivially, since this only takes effect
*  on the client side
* <li> {@link ConstraintAlternatives}, if the elements all have the same
*  actual class and at least one element is supported
* <li> {@link Delegation#NO}
* <li> {@link Delegation#YES}, trivially, for anonymous clients
* <li> {@link DelegationAbsoluteTime}, trivially, when delegation is not
*  supported
* <li> {@link DelegationRelativeTime}, trivially, when delegation is not
*  supported
* <li> {@link Integrity#YES}
* <li> {@link ServerAuthentication}
* <li> {@link ServerMinPrincipal}, when it contains a single
<code>X500Principal</code> only
* </ul> <p>
*
* This class authenticates as a single {@link Principal} if the following
* items are present in the server {@link Subject}: <p>
*
* <ul>
* <li> One or more principals of type <code>X500Principal</code>
* <li> For each principal, one or more certificate chains, stored as public
*      credentials, and represented by instances of {@link CertPath}, whose
*      <code>getType</code> method returns "X.509", and for which calling
*      <code>getSubjectDN</code> on the certificate chain's first element
*      returns that principal's name
* <li> For each certificate chain, an instance of {@link
*      X500PrivateCredential}, stored as a private credential, whose
*      <code>getCertificate</code> method returns a value equal to the first
*      element of the certificate chain, and whose <code>getPrivateKey</code>
*      method returns the associated private key
* </ul> <p>
*
* In addition, this class will only dispatch remote calls that authenticate as
* a given principal if the caller of {@link
* net.jini.jeri.ServerEndpoint.ListenEndpoint#listen listen} on the class's
* {@link net.jini.jeri.ServerEndpoint.ListenEndpoint} has been granted {@link
* AuthenticationPermission} with that principal as the local principal, the
* principal representing the authenticated identity of the client for the call
* (if any) as the peer principal, and the <code>accept</code> action. <p>
*
* This class supports remote connections between authenticated servers and
* authenticated or anonymous clients, and between anonymous servers and
* anonymous clients. Connections between anonymous servers and authenticated
* clients are not supported. Because of the suites available in the TLS/SSL
* protocol, support for {@link Confidentiality#NO} requires the server to
* authenticate with an RSA public key. <p>
*
* If the server subject contains principals and credentials that would permit
* authentication of more than one <code>X500Principal</code>, the endpoint
* will make an arbitrary choice of the principal to use for authentication,
* and will continue to make the same choice so long as subject contents,
* validity of credentials, and security permissions do not change. <p>
*
* The host name specified when creating an <code>HttpsServerEndpoint</code>
* instance controls the host name that will be contained in
* <code>HttpsEndpoint</code> instances produced when {@link
* #enumerateListenEndpoints enumerateListenEndpoints} is invoked to listen on
* the server endpoint; the host name does not affect the behavior of the
* listen operation itself, which listens on all of the local system's network
* addresses. If the host name in the server endpoint is <code>null</code>,
* then the host name in the <code>HttpsEndpoint</code> instances that it
* produces will be the default server host name, which is the IP address
* string of the {@link InetAddress} returned by {@link
* InetAddress#getLocalHost InetAddress.getLocalHost} when
* <code>enumerateListenEndpoints</code> is invoked. <p>
*
* This class permits specifying a {@link SocketFactory} for creating the
* {@link Socket} instances that the associated <code>HttpsEndpoint</code>
* instances use to make remote connections back to the server, and a {@link
* ServerSocketFactory} for creating the {@link ServerSocket} instances that
* the server endpoint uses to accept remote connections. These socket
* factories and sockets should not implement the TLS/SSL protocol; it is the
* responsibility of the implementation to establish TLS/SSL connections over
* the sockets it obtains from the socket factories. In particular, instances
* of {@link SSLSocketFactory} and {@link SSLServerSocketFactory} should not be
* used, and the factories used should not return instances of {@link
* SSLSocket} or {@link SSLServerSocket}. <p>
*
* A <code>SocketFactory</code> used with instances of this class should be
* serializable, and must implement {@link Object#equals Object.equals} to obey
* the guidelines that are specified for <code>equals</code> methods of {@link
* Endpoint} instances. A <code>ServerSocketFactory</code> used with instances
* of this class must implement <code>Object.equals</code> to obey the
* guidelines that are specified for <code>equals</code> methods of {@link
* net.jini.jeri.ServerEndpoint.ListenEndpoint ListenEndpoint} instances.
*
* @author Sun Microsystems, Inc.
* @see HttpsEndpoint
* @see ConfidentialityStrength
* @since 2.0
*
* @com.sun.jini.impl <!-- Implementation Specifics -->
*
* This implementation uses the <a
* href="http://java.sun.com/j2se/1.4/docs/guide/security/jsse/JSSERefGuide.html"
* target="_top">Java(TM) Secure Socket Extension (JSSE)</a>. <p>
*
* This implementation uses the {@link ServerConnectionManager} class to manage
* connections. <p>
*
* This implementation uses the following {@link Logger} instances in the
* <code>net.jini.jeri.ssl</code> namespace: <p>
*
* <ul>
* <li> <a href="#init_logger">init</a> - problems during initialization
* <li> <a href="#server_logger">server</a> - information about
*  server-side connections
* </ul> <p>
*
* <a name="init_logger"></a>
* <table border="1" cellpadding="5" summary="Describes logging to the init
*    logger performed by the HttpsServerEndpoint class at different
*    logging levels">
*
* <caption halign="center" valign="top"><b><code>
*      net.jini.jeri.ssl.init</code></b></caption>
*    
* <tr> <th scope="col"> Level <th scope="col"> Description
*
* <tr> <td> {@link Level#WARNING WARNING} <td> problems with initializing JSSE
*
* </table> <p>
*
* <a name="server_logger"></a>
* <table border="1" cellpadding="5" summary="Describes logging to the server
*    logger performed by the HttpsServerEndpoint class at different
*    logging levels">
*
* <caption halign="center" valign="top"><b><code>
*      net.jini.jeri.ssl.server</code></b></caption>
*    
* <tr> <th scope="col"> Level <th scope="col"> Description
*
* <tr> <td> {@link Level#INFO INFO} <td> problems with accepting or handling
* server connections, or with handling inbound requests
*
* <tr> <td> {@link Levels#FAILED FAILED} <td> problems with checking
* constraints or permissions, with enumerating listen endpoints, or with
* security issues for inbound requests
*
* <tr> <td> {@link Levels#HANDLED HANDLED} <td> exceptions caught involving
* authentication
*
* <tr> <td> {@link Level#FINE FINE} <td> creating server endpoints,
* enumerating listen endpoints, creating or closing connections or listen
* handles, or checking constraints for endpoints or inbound requests
*
* <tr> <td> {@link Level#FINEST FINEST} <td> low level operation tracing
*
* </table> <p>
*
* This implementation uses the following security providers: <p>
*
* <ul>
* <li> {@link SSLContext}, with the protocol specified by the
<code>com.sun.jini.jeri.ssl.sslProtocol</code> system property, or
<code>"TLS"</code> if that property is not defined, to provide the
*  TLS/SSL implementation. The {@link SSLContext#init SSLContext.init}
*  method is called with <code>null</code> for the <code>random</code>
*  parameter to use the default {@link SecureRandom} implementation.
* <li> {@link CertificateFactory}, with type <code>"X.509"</code>, to generate
<code>CertPath</code> instances from X.509 certificate chains
* <li> {@link TrustManagerFactory}, with the algorithm specified by the
<code>com.sun.jini.jeri.ssl.trustManagerFactoryAlgorithm</code> system
*  property, or the default algorithm if that property is not defined, to
*  implement trust management for the TLS/SSL implementation. The factory
*  must return trust managers that implement {@link X509TrustManager}.
* </ul> <p>
*
* See the documentation on <a
* href="http://java.sun.com/j2se/1.4/docs/guide/security/CryptoSpec.html#ProviderInstalling"
* target="_top">installing security providers</a> and <a
* href="http://java.sun.com/j2se/1.4/docs/guide/security/jsse/JSSERefGuide.html#ProviderCust"
* target="_top">configuring JSSE</a> for information on configuring these
* providers. <p>
*
* The <a
* href="http://java.sun.com/j2se/1.4/docs/guide/security/jsse/JSSERefGuide.html#Customization"
* target="_top">JSSE documentation</a> also describes the system properties
* for configuring the location, type, and password of the truststore that this
* implementation uses, through JSSE, to make decisions about what certificate
* chains should be trusted. <p>
*
* This implementation recognizes the following system properties: <p>
*
* <ul>
* <li> <code>com.sun.jini.jeri.ssl.maxServerSessionDuration</code> - The
*  maximum number of milliseconds a server-side TLS/SSL session should be
*  used before expiring. The default is 24 hours. The value used should be
*  larger than the maximum client session duration to allow the client to
*  negotiate a new session before the server timeout occurs.
* <li> <code>com.sun.jini.jeri.ssl.sslProtocol</code> - The secure socket
*  protocol used when obtaining {@link SSLContext} instances. The default
*  is <code>"TLS"</code>.
* <li> <code>com.sun.jini.jeri.ssl.trustManagerFactoryAlgorithm</code> - The
*  algorithm used when obtaining {@link TrustManagerFactory}
*  instances. The default is the value returned by {@link
*  TrustManagerFactory#getDefaultAlgorithm
*  TrustManagerFactory.getDefaultAlgorithm}.
* <li> <code>com.sun.jini.jeri.ssl.cipherSuites</code> - The TLS/SSL cipher
*  suites that should be used for communication. The default is the list
*  of suites supported by the JSSE implementation. The value should
*  specify the suite names, separated by commas. The value will be ignored
*  if it contains no suites or specifies suites that are not supported by
*  the JSSE implementation. Suites appearing earlier in the list will be
*  preferred to ones appearing later for suites that support the same
*  requirements and preferences.
* <li> <code>com.sun.jini.jeri.https.idleServerConnectionTimeout</code> - The
*  number of milliseconds to retain idle server-side HTTPS connections
*  before closing them. The default is the idle client-side connection
*  timeout (as specified by the
<code>com.sun.jini.jeri.https.idleConnectionTimeout</code> system
*  property) plus <code>30000</code>.
* <li> <code>com.sun.jini.jeri.https.responseAckTimeout</code> - The number of
*  milliseconds to wait for acknowledgments from {@link
*  AcknowledgmentSource} instances. The default is <code>15000</code>.
* </ul>
*/
public final class HttpsServerEndpoint implements ServerEndpoint {

    /* -- Fields -- */

    /** Server logger */
    static final Logger logger = Utilities.serverLogger;

    /** Manager for HTTP server connections. */
    static final HttpServerManager httpServerManager;

    /** Times out idle connections. */
    static final ConnectionTimer connectionTimer;

    static {
  HttpSettings hs = HttpsEndpoint.getHttpSettings();
  httpServerManager = new HttpServerManager(hs.getResponseAckTimeout());
  connectionTimer = new ConnectionTimer(hs.getServerConnectionTimeout());
    }

    /** Implementation delegate. */
    private final HttpsServerEndpointImpl impl;

    /* -- Methods -- */

    /**
     * Returns an HTTPS server endpoint for the specified port. Uses the
     * <code>null</code> server host (which requests that {@link
     * #enumerateListenEndpoints enumerateListenEndpoints} compute the default
     * server host), the subject associated with the current access control
     * context, the principals in the subject with appropriate public and
     * private credentials for which the caller has {@link
     * AuthenticationPermission} to listen, and <code>null</code> socket
     * factories to create default sockets. A <code>port</code> of
     * <code>0</code> requests listening on any free port.
     *
     * @param port the port on which to listen for connections, or
     *        <code>0</code> for any free port
     * @return an <code>HttpsServerEndpoint</code> instance
     * @throws IllegalArgumentException if <code>port</code> is negative or
     *         greater than <code>65535</code>
     */
    public static HttpsServerEndpoint getInstance(int port) {
  return new HttpsServerEndpoint(null, null, null, port, null, null);
    }

    /**
     * Returns an HTTPS server endpoint for the specified server host and port.
     * Uses the subject associated with the current access control context, the
     * principals in the subject with appropriate public and private
     * credentials for which the caller has {@link AuthenticationPermission} to
     * listen, and <code>null</code> socket factories to create default
     * sockets. A <code>serverHost</code> of <code>null</code> requests that
     * {@link #enumerateListenEndpoints enumerateListenEndpoints} compute the
     * default server host. A <code>port</code> of <code>0</code> requests
     * listening on any free port.
     *
     * @param serverHost the name that clients should use to connect to this
     *        server, or <code>null</code> to use the default
     * @param port the port on which to listen for connections, or
     *        <code>0</code> for any free port
     * @return an <code>HttpsServerEndpoint</code> instance
     * @throws IllegalArgumentException if <code>port</code> is negative or
     *         greater than <code>65535</code>
     */
    public static HttpsServerEndpoint getInstance(String serverHost, int port) {
  return new HttpsServerEndpoint(
      null, null, serverHost, port, null, null);
    }

    /**
     * Returns an HTTPS server endpoint for the specified server host, port,
     * and socket factories. Uses the subject associated with the current
     * access control context, and the principals in the subject with
     * appropriate public and private credentials for which the caller has
     * {@link AuthenticationPermission} to listen. A <code>serverHost</code> of
     * <code>null</code> requests that {@link #enumerateListenEndpoints
     * enumerateListenEndpoints} compute the default server host. A
     * <code>port</code> of <code>0</code> requests listening on any free
     * port. A <code>socketFactory</code> of <code>null</code> uses default
     * sockets in the associated {@link HttpsEndpoint}. A
     * <code>serverSocketFactory</code> of <code>null</code> uses default
     * server sockets.
     *
     * @param serverHost the name that clients should use to connect to this
     *        server, or <code>null</code> to use the default
     * @param port the port on which to listen for connections, or
     *        <code>0</code> for any free port
     * @param socketFactory the socket factory for use in the associated
     *        <code>HttpsEndpoint</code> instances, or <code>null</code>
     * @param serverSocketFactory the server socket factory, or
     *        <code>null</code>
     * @return an <code>HttpsServerEndpoint</code> instance
     * @throws IllegalArgumentException if <code>port</code> is negative or
     *         greater than <code>65535</code>
     */
    public static HttpsServerEndpoint getInstance(
  String serverHost,
  int port,
  SocketFactory socketFactory,
  ServerSocketFactory serverSocketFactory)
    {
  return new HttpsServerEndpoint(null, null, serverHost, port,
               socketFactory, serverSocketFactory);
    }

    /**
     * Returns an HTTPS server endpoint for the specified server subject,
     * server principals, server host, and port. Uses <code>null</code> socket
     * factories to create default sockets. A <code>serverSubject</code> of
     * <code>null</code> uses the subject associated with the current access
     * control context. A <code>serverPrincipals</code> of <code>null</code>
     * uses the principals in the subject with appropriate public and private
     * credentials for which the caller has {@link AuthenticationPermission} to
     * listen; otherwise that argument specifies the principals to use, or that
     * the server should be anonymous if the argument has no elements.  If
     * non-<code>null</code>, the value of <code>serverPrincipals</code> is
     * neither retained nor modified; subsequent changes to that argument have
     * no effect on the instance created. A <code>serverHost</code> of
     * <code>null</code> requests that {@link #enumerateListenEndpoints
     * enumerateListenEndpoints} compute the default server host. A
     * <code>port</code> of <code>0</code> requests listening on any free port.
     *
     * @param serverSubject the <code>Subject</code> to use for authenticating
     *        the server or <code>null</code> to use the current subject
     * @param serverPrincipals the principals to use for authenticating the
     *        server, or <code>null</code> to use any available principals in
     *        the subject
     * @param serverHost the name that clients should use to connect to this
     *        server, or <code>null</code> to use the default
     * @param port the port on which to listen for connections, or
     *        <code>0</code> for any free port
     * @return an <code>HttpsServerEndpoint</code> instance
     * @throws IllegalArgumentException if <code>port</code> is negative or
     *         greater than <code>65535</code>
     * @throws NullPointerException if <code>serverPrincipals</code> is not
     *         <code>null</code> and any of its elements are <code>null</code>
     */
    public static HttpsServerEndpoint getInstance(
  Subject serverSubject,
  X500Principal[] serverPrincipals,
  String serverHost,
  int port)
    {
  return new HttpsServerEndpoint(serverSubject, serverPrincipals,
               serverHost, port, null, null);
    }

    /**
     * Returns an HTTPS server endpoint for the specified server subject,
     * server principals, server host, port, and socket factories. A
     * <code>serverSubject</code> of <code>null</code> uses the subject
     * associated with the current access control context. A
     * <code>serverPrincipals</code> of <code>null</code> uses the principals
     * in the subject with appropriate public and private credentials for which
     * the caller has {@link AuthenticationPermission} to listen; otherwise
     * that argument specifies the principals to use, or that the server should
     * be anonymous if the argument has no elements. If non-<code>null</code>,
     * the value of <code>serverPrincipals</code> is neither retained nor
     * modified; subsequent changes to that argument have no effect on the
     * instance created. A <code>serverHost</code> of <code>null</code>
     * requests that {@link #enumerateListenEndpoints enumerateListenEndpoints}
     * compute the default server host. A <code>port</code> of <code>0</code>
     * requests listening on any free port. A <code>socketFactory</code> of
     * <code>null</code> uses default sockets in the associated {@link
     * HttpsEndpoint}. A <code>serverSocketFactory</code> of <code>null</code>
     * uses default server sockets.
     *
     * @param serverSubject the <code>Subject</code> to use for authenticating
     *        the server or <code>null</code> to use the current subject
     * @param serverPrincipals the principals to use for authenticating the
     *        server, or <code>null</code> to use any available principals in
     *        the subject
     * @param serverHost the name that clients should use to connect to this
     *        server, or <code>null</code> to use the default
     * @param port the port on which to listen for connections, or
     *        <code>0</code> for any free port
     * @param socketFactory the socket factory for use in the associated
     *        <code>HttpsEndpoint</code> instances, or <code>null</code>
     * @param serverSocketFactory the server socket factory, or
     *        <code>null</code>
     * @return an <code>HttpsServerEndpoint</code> instance
     * @throws IllegalArgumentException if <code>port</code> is negative or
     *         greater than <code>65535</code>
     * @throws NullPointerException if <code>serverPrincipals</code> is not
     *         <code>null</code> and any of its elements are <code>null</code>
     */
    public static HttpsServerEndpoint getInstance(
  Subject serverSubject,
  X500Principal[] serverPrincipals,
  String serverHost,
  int port,
  SocketFactory socketFactory,
  ServerSocketFactory serverSocketFactory)
    {
  return new HttpsServerEndpoint(serverSubject, serverPrincipals,
               serverHost, port, socketFactory,
               serverSocketFactory);
    }

    /** Creates an instance of this class. */
    private HttpsServerEndpoint(Subject serverSubject,
        X500Principal[] serverPrincipals,
        String serverHost,
        int port,
        SocketFactory socketFactory,
        ServerSocketFactory serverSocketFactory)
    {
  impl = new HttpsServerEndpointImpl(
      this, serverSubject, serverPrincipals,
      serverHost, port, socketFactory, serverSocketFactory);
  logger.log(Level.FINE, "created {0}", this);
    }

    /**
     * Returns the host name that will be used in {@link HttpsEndpoint}
     * instances created by listening on this object, or <code>null</code> if
     * {@link #enumerateListenEndpoints enumerateListenEndpoints} will
     * use the default server host.
     *
     * @return the host name to use in <code>HttpsEndpoint</code> instances
     *         created by listening on this object, or <code>null</code> if
     *         using the default
     */
    public String getHost() {
  return impl.serverHost;
    }

    /**
     * Returns the TCP port on which this object listens for connections, or
     * <code>0</code> if it selects a free port.
     *
     * @return the TCP port on which this object listens for connections, or
     *         <code>0</code> if it selects a free port
     */
    public int getPort() {
  return impl.port;
    }

    /**
     * Returns an immutable set of the principals that this instance uses for
     * authentication, or <code>null</code> if it is anonymous.
     *
     * @return an immutable set of the principals or <code>null</code>
     */
    public Set getPrincipals() {
  return impl.serverPrincipals == null
      ? null : Collections.unmodifiableSet(impl.serverPrincipals);
    }

    /**
     * Returns the socket factory that the associated {@link HttpsEndpoint}
     * instances created by listening on this server endpoint use to create
     * {@link Socket} instances, or <code>null</code> if they use default
     * sockets.
     *
     * @return the socket factory that associated endpoints use to create
     *         sockets, or <code>null</code> if they use default sockets
     */
    public SocketFactory getSocketFactory() {
  return impl.socketFactory;
    }

    /**
     * Returns the server socket factory that this server endpoint uses to
     * create {@link ServerSocket} instances, or <code>null</code> if it uses
     * default server sockets.
     *
     * @return the server socket factory that this server endpoint uses to
     *         create server sockets, or <code>null</code> if it uses default
     *         server sockets
     */
    public ServerSocketFactory getServerSocketFactory() {
  return impl.serverSocketFactory;
    }

    /** Returns a string representation of this object. */
    public String toString() {
  return "HttpsServerEndpoint" + impl.fieldsToString();
    }

    /* -- Implement ServerCapabilities -- */

    /**
     * Checks that it is possible to receive requests that either
     * fully or partially satisfy the specified requirements, and
     * returns any constraints that must be fully or partially
     * implemented by higher layers in order to fully satisfy all of
     * the specified requirements. <p>
     *
     * This implementation only returns {@link Integrity#YES} constraints.
     *
     * @throws SecurityException if the current security context does not have
     *         the permissions necessary to perform this operation
     * @throws NullPointerException if <code>constraints</code> is
     *         <code>null</code>
     */
    public InvocationConstraints checkConstraints(
  InvocationConstraints constraints)
  throws UnsupportedConstraintException
    {
  return impl.checkConstraints(constraints);
    }

    /* -- Implement ServerEndpoint -- */

    /** Returns a hash code value for this object. */
    public int hashCode() {
  return impl.hashCode();
    }

    /**
     * Two instances of this class are equal if they have server subjects that
     * compare equal using <code>==</code>; have server principals that are
     * either both <code>null</code> or are equal when compared as the elements
     * of a {@link Set}; have the same values for server host and port; have
     * socket factories that are either both <code>null</code>, or have the
     * same actual class and are equal; and have server socket factories that
     * are either both <code>null</code>, or have the same actual class and are
     * equal.
     */
    public boolean equals(Object object) {
  if (this == object) {
      return true;
  } else {
      return object instanceof HttpsServerEndpoint &&
    impl.equals(((HttpsServerEndpoint) object).impl);
  }
    }

    /**
     * Passes the {@link net.jini.jeri.ServerEndpoint.ListenEndpoint
     * ListenEndpoint} for this <code>HttpsServerEndpoint</code> to
     * <code>listenContext</code>, which will ensure an active listen
     * operation on the endpoint, and returns an <code>HttpsEndpoint</code>
     * instance corresponding to the listen operation chosen by
     * <code>listenContext</code>. <p>
     *
     * If this server endpoint's server host is <code>null</code>, then the
     * endpoint returned will contain the default server host. This method
     * computes the default by invoking {@link InetAddress#getLocalHost
     * InetAddress.getLocalHost} to obtain an <code>InetAddress</code> for the
     * local host. If <code>InetAddress.getLocalHost</code> throws an
     * exception, this method throws that exception. The default host name will
     * be the string returned by invoking {@link InetAddress#getHostAddress
     * getHostAddress} on that <code>InetAddress</code>. If there is a security
     * manager, its {@link SecurityManager#checkConnect(String,int)
     * checkConnect} method will be invoked with the string returned by
     * invoking {@link InetAddress#getHostName getHostName} on that same
     * <code>InetAddress</code> as the host argument and <code>-1</code> as the
     * port argument; this could result in a
     * <code>SecurityException</code>. <p>
     *
     * This method invokes <code>addListenEndpoint</code> on
     * <code>listenContext</code> once, passing a <code>ListenEndpoint</code>
     * as described below.  If <code>addListenEndpoint</code> throws an
     * exception, then this method throws that exception.  Otherwise, this
     * method returns an <code>HttpsEndpoint</code> instance with the host name
     * described above, the TCP port number bound by the listen operation
     * represented by the {@link net.jini.jeri.ServerEndpoint.ListenHandle
     * ListenHandle} returned by <code>addListenEndpoint</code>, and the same
     * <code>SocketFactory</code> as this <code>HttpsServerEndpoint</code>. <p>
     *
     * The <code>ListenEndpoint</code> passed to
     * <code>addListenEndpoint</code> represents the server subject, server
     * principals, TCP port number, and <code>ServerSocketFactory</code> of
     * this <code>HttpsServerEndpoint</code>.  Its methods behave as follows:
     * <p>
     *
     * {@link net.jini.jeri.ServerEndpoint.ListenEndpoint#listen ListenHandle
     * listen(RequestDispatcher)}:
     *
     * <blockquote>
     *
     * Listens for requests received on this endpoint's TCP port, dispatching
     * them to the supplied <code>RequestDispatcher</code> in the form of
     * {@link InboundRequest} instances. <p>
     *
     * When the implementation of this method needs to create a new
     * <code>ServerSocket</code>, it will do so by invoking one of the
     * <code>createServerSocket</code> methods that returns a bound server
     * socket on the contained <code>ServerSocketFactory</code> if
     * non-<code>null</code>, or it will create a <code>ServerSocket</code>
     * directly otherwise. <p>
     *
     * If there is a security manager, its {@link SecurityManager#checkListen
     * checkListen} method will be invoked with this endpoint's TCP port; this
     * could result in a <code>SecurityException</code>. In addition, for each
     * server principal in this endpoint, the security manager's {@link
     * SecurityManager#checkPermission checkPermission} method will be invoked
     * with an {@link AuthenticationPermission} containing the server
     * principal and the <code>listen</code> action; this could also result in
     * a <code>SecurityException</code>.  Furthermore, before a given
     * <code>InboundRequest</code> gets dispatched to the supplied request
     * dispatcher, the security manager's {@link SecurityManager#checkAccept
     * checkAccept} method must have been successfully invoked in the security
     * context of this <code>listen</code> invocation with the remote IP
     * address and port of the <code>Socket</code> used to receive the
     * request, and if the server authenticated itself to the client, the
     * security manager's <code>checkPermission</code> method must have been
     * successfully invoked in the same context with an
     * <code>AuthenticationPermission</code> containing that authenticated
     * server principal as local principal, the client's authenticated
     * principal (if any) as peer principal, and the <code>accept</code>
     * action. The <code>checkPermissions</code> method of the dispatched
     * <code>InboundRequest</code> also performs these latter security checks.
     * (Note that in some cases, the implementation may carry out some of
     * these security checks indirectly, such as through invocations of
     * <code>ServerSocket</code>'s constructors or <code>accept</code>
     * method.) <p>
     *
     * Requests will be dispatched in a {@link PrivilegedAction} wrapped by a
     * {@link SecurityContext} obtained when this method was invoked, with the
     * {@link AccessControlContext} of that <code>SecurityContext</code> in
     * effect. <p>
     *
     * Dispatched requests will implement {@link
     * InboundRequest#populateContext populateContext} to populate the given
     * collection with an element that implements the {@link ClientHost}
     * interface, and an element that implements the {@link ClientSubject}
     * interface. The <code>ClientHost</code> element implements {@link
     * ClientHost#getClientHost getClientHost} to return the IP address of the
     * <code>Socket</code> that the request was received over (see {@link
     * Socket#getInetAddress}). <p>
     *
     * Throws {@link IOException} if an I/O exception occurs while performing
     * this operation, such as if the TCP port is already in use. <p>
     *
     * Throws {@link SecurityException} if there is a security manager and an
     * invocation of its <code>checkListen</code> or
     * <code>checkPermission</code> method fails. <p>
     *
     * Throws {@link NullPointerException} if <code>requestDispatcher</code>
     * is <code>null</code>
     *
     * </blockquote>
     *
     * {@link net.jini.jeri.ServerEndpoint.ListenEndpoint#checkPermissions
     * void checkPermissions()}:
     *
     * <blockquote>
     *
     * Verifies that the current security context has all of the security
     * permissions necessary to listen for requests on this endpoint. <p>
     *
     * If there is a security manager, its <code>checkListen</code> method
     * will be invoked with this endpoint's TCP port; this could result in a
     * <code>SecurityException</code>. In addition, for each server principal
     * in this endpoint, the security manager's {@link
     * SecurityManager#checkPermission checkPermission} method will be invoked
     * with an {@link AuthenticationPermission} containing the server
     * principal and the <code>listen</code> action; this could also result in
     * a <code>SecurityException</code>. <p>
     *
     * Throws {@link SecurityException} if there is a security manager and an
     * invocation of its <code>checkListen</code> or
     * <code>checkPermission</code> method fails.
     *
     * </blockquote>
     *
     * {@link Object#equals boolean equals(Object)}:
     *
     * <blockquote>
     *
     * Compares the specified object with this <code>ListenEndpoint</code> for
     * equality. <p>
     *
     * This method returns <code>true</code> if and only if the specified
     * object is also a <code>ListenEndpoint</code> produced by an
     * <code>HttpsServerEndpoint</code>, and the two listen endpoints both have
     * server subjects that compare equal using <code>==</code>; have server
     * principals that are either both <code>null</code> or are equal when
     * compared as the elements of a {@link Set}; have the same values for TCP
     * port; and have server socket factories that are either both
     * <code>null</code>, or have the same actual class and are equal.
     *
     * </blockquote>
     *
     * @throws SecurityException if there is a security manager, and either its
     *         {@link SecurityManager#checkListen checkListen} method fails,
     *         or <code>serverHost</code> is <code>null</code> and the security
     *         manager's {@link SecurityManager#checkConnect checkConnect}
     *         method fails; or if the calling thread does not have permission
     *         to authenticate as each of the endpoint's server principals when
     *         listening for connections
     * @throws IllegalArgumentException if an invocation of the
     *         <code>addListenEndpoint</code> method on the supplied
     *         <code>ListenContext</code> returns a <code>ListenCookie</code>
     *         that does not correspond to the <code>ListenEndpoint</code> that
     *         was passed to it
     * @throws NullPointerException if <code>listenContext</code> is
     *         <code>null</code>
     * @throws UnknownHostException if this instance's server host
     *         is <code>null</code> and <code>InetAddress.getLocalHost</code>
     *         throws an <code>UnknownHostException</code>
     * @throws UnsupportedConstraintException if the server subject is missing
     *         any of the endpoint's server principals or the associated
     *         credentials
     */
    public Endpoint enumerateListenEndpoints(ListenContext listenContext)
  throws IOException
    {
  return impl.enumerateListenEndpoints(listenContext);
    }

    /** Implementation delegate. */
    private static final class HttpsServerEndpointImpl
  extends SslServerEndpointImpl
    {
  HttpsServerEndpointImpl(ServerEndpoint serverEndpoint,
        Subject serverSubject,
        X500Principal[] serverPrincipals,
        String serverHost,
        int port,
        SocketFactory socketFactory,
        ServerSocketFactory serverSocketFactory)
  {
      super(serverEndpoint, serverSubject, serverPrincipals,
      serverHost, port, socketFactory, serverSocketFactory);
  }

  ListenEndpoint createListenEndpoint() {
      return new HttpsListenEndpoint();
  }

  Endpoint createEndpoint(String serverHost, SslListenCookie cookie) {
      return HttpsEndpoint.getInstance(
    serverHost, cookie.getPort(), socketFactory);
  }

  /** Implements ListenEndpoint */
  private final class HttpsListenEndpoint extends SslListenEndpoint {

      ListenHandle createListenHandle(RequestDispatcher requestDispatcher,
              ServerSocket serverSocket)
    throws IOException
      {
    return new HttpsListenHandle(requestDispatcher, serverSocket);
      }
  }

  /** Implements ListenHandle */
  private final class HttpsListenHandle extends SslListenHandle {

      HttpsListenHandle(RequestDispatcher requestDispatcher,
            ServerSocket serverSocket)
    throws IOException
      {
    super(requestDispatcher, serverSocket);
      }

      SslServerConnection serverConnection(Socket socket)
    throws IOException
      {
    return new HttpsServerConnection(this, socket);
      }

      void handleConnection(SslServerConnection connection,
          RequestDispatcher requestDispatcher)
      {
    try {
        new HttpServer(
      connection.sslSocket,
      new HttpsRequestDispatcher(
          requestDispatcher,
          (HttpsServerConnection) connection),
      (HttpsServerConnection) connection);
    } catch (IOException e) {
        if (logger.isLoggable(Level.INFO)) {
      logThrow(logger, Level.INFO,
         HttpsListenHandle.class, "handleConnection",
         "{0} throws", new Object[] { connection },
         e);
        }
        try {
      connection.close();
        } catch (IOException e2) {
        }
    }
      }
  }

  /**
   * An HTTP server connection that gets its client host from the HTTPS
   * connection and closes the HTTPS connection when it shuts down.
   */
  private static final class HttpServer extends HttpServerConnection {

      private final HttpsServerConnection connection;

      HttpServer(Socket socket,
           RequestDispatcher requestDispatcher,
           HttpsServerConnection connection)
    throws IOException
      {
    super(socket, requestDispatcher, httpServerManager);
    this.connection = connection;
    connection.httpServer = this;
    start();
      }

      /** Not called -- handled by inbound request */
      protected void checkPermissions() {
    throw new AssertionError();
      }

      /** No additional context -- supplied by inbound request */
      protected void populateContext(Collection context) { }

      /** Not called -- handled by inbound request */
      protected InvocationConstraints checkConstraints(
    InvocationConstraints constraints)
      {
    throw new AssertionError();
      }

      /** Schedules the connection to close after an idle timeout. */
      protected void idle() {
    connectionTimer.scheduleTimeout(this, false);
      }

      /** Cancels the idle timeout. */
      protected void busy() {
    connectionTimer.cancelTimeout(this);
      }

      /** Closes the associated secure connection. */
      public boolean shutdown(boolean force) {
    boolean result = super.shutdown(force);
    if (result) {
        try {
      connection.close();
        } catch (IOException e) {
        }
    }
    connectionTimer.cancelTimeout(this);
    return result;
      }
  }

  /**
   * Implements RequestDispatcher using the specified RequestDispatcher
   * and ServerConnection.
   */
  private static final class HttpsRequestDispatcher extends Utilities
      implements RequestDispatcher
  {
      private final RequestDispatcher requestDispatcher;
      private final HttpsServerConnection connection;

      HttpsRequestDispatcher(RequestDispatcher requestDispatcher,
           HttpsServerConnection connection)
      {
    this.requestDispatcher = requestDispatcher;
    this.connection = connection;
      }

      public void dispatch(InboundRequest request) {
    try {
        InboundRequest wrappedRequest =
      new HttpsInboundRequest(
          request, connection,
          connection.processRequestData(
        request.getRequestInputStream(),
        request.getResponseOutputStream()));
        wrappedRequest.checkPermissions();
        requestDispatcher.dispatch(wrappedRequest);
    } catch (SecurityException e) {
        if (logger.isLoggable(Level.INFO)) {
      logThrow(
          logger, Level.INFO,
          HttpsRequestDispatcher.class, "dispatch",
          "{0} throws", new Object[] { connection }, e);
        }
    }
      }
  }

  /** Implements InboundRequest */
  private static final class HttpsInboundRequest
      implements InboundRequest
  {
      private final InboundRequest request;
      private final ServerConnection connection;
      private final InboundRequestHandle handle;

      HttpsInboundRequest(InboundRequest request,
        ServerConnection connection,
        InboundRequestHandle handle)
      {
    this.request = request;
    this.connection = connection;
    this.handle = handle;
      }

      /* Delegate to connection */
      public void checkPermissions() {
    connection.checkPermissions(handle);
      }

      /* Delegate to connection */
      public InvocationConstraints checkConstraints(
    InvocationConstraints constraints)
    throws UnsupportedConstraintException
      {
    return connection.checkConstraints(handle, constraints);
      }

      /* Delegate to both the underlying request and the connection. */
      public void populateContext(Collection context) {
    request.populateContext(context);
    connection.populateContext(handle, context);
      }

      /* Delegate to underlying request */
      public InputStream getRequestInputStream() {
    return request.getRequestInputStream();
      }

      /* Delegate to underlying request */
      public OutputStream getResponseOutputStream() {
    return request.getResponseOutputStream();
      }

      /* Delegate to underlying request */
      public void abort() {
    request.abort();
      }
  }

  /** Implements ServerConnection. */
  private final class HttpsServerConnection extends SslServerConnection {

      /** The HTTP server connection */
      HttpServer httpServer;

      /** Creates a server connection. */
      HttpsServerConnection(HttpsListenHandle listenHandle, Socket socket)
    throws IOException
      {
    super(listenHandle, socket);
      }

      void closeInternal(boolean removeFromListener) throws IOException {
    synchronized (this) {
        if (closed) {
      return;
        }
    }
    super.closeInternal(removeFromListener);
    /* Close the associated HTTP connection */
    if (httpServer != null) {
        httpServer.shutdown(true);
        httpServer = null;
    }
      }
  }
    }
}
TOP

Related Classes of net.jini.jeri.ssl.HttpsServerEndpoint$HttpsServerEndpointImpl$HttpsServerConnection

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.