Package com.sun.jmx.remote.opt.security

Source Code of com.sun.jmx.remote.opt.security.AdminServer

/*
* @(#)file      AdminServer.java
* @(#)author    Sun Microsystems, Inc.
* @(#)version   1.37
* @(#)lastedit  07/03/08
* @(#)build     @BUILD_TAG_PLACEHOLDER@
*
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
*
* The contents of this file are subject to the terms of either the GNU General
* Public License Version 2 only ("GPL") or the Common Development and
* Distribution License("CDDL")(collectively, the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy of the
* License at http://opendmk.dev.java.net/legal_notices/licenses.txt or in the
* LEGAL_NOTICES folder that accompanied this code. See the License for the
* specific language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file found at
*     http://opendmk.dev.java.net/legal_notices/licenses.txt
* or in the LEGAL_NOTICES folder that accompanied this code.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code.
*
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
*
*       "Portions Copyrighted [year] [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding
*
*       "[Contributor] elects to include this software in this distribution
*        under the [CDDL or GPL Version 2] license."
*
* If you don't indicate a single choice of license, a recipient has the option
* to distribute your version of this file under either the CDDL or the GPL
* Version 2, or to extend the choice of license to its licensees as provided
* above. However, if you add GPL Version 2 code and therefore, elected the
* GPL Version 2 license, then the option applies only if the new code is made
* subject to such option by the copyright holder.
*
*/

package com.sun.jmx.remote.opt.security;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.WeakHashMap;

import javax.management.remote.JMXAuthenticator;
import javax.management.remote.generic.MessageConnection;
import javax.management.remote.message.Message;
import javax.management.remote.message.HandshakeBeginMessage;
import javax.management.remote.message.HandshakeEndMessage;
import javax.management.remote.message.HandshakeErrorMessage;
import javax.management.remote.message.VersionMessage;
import javax.management.remote.message.ProfileMessage;
import javax.security.auth.Subject;

import com.sun.jmx.remote.generic.CheckProfiles;
import com.sun.jmx.remote.generic.ProfileServer;
import com.sun.jmx.remote.generic.ProfileServerFactory;
import com.sun.jmx.remote.generic.ServerAdmin;
import com.sun.jmx.remote.opt.util.ClassLogger;
import com.sun.jmx.remote.socket.SocketConnectionIf;

/**
*
*/
public class AdminServer implements ServerAdmin {

    public AdminServer(Map env) {
  this.env = (env != null) ? env : Collections.EMPTY_MAP;
    }

    public MessageConnection connectionOpen(MessageConnection mc)
      throws IOException {

  boolean sendError = true;

  try {

      // Initialize the Subject that will be passed to all
      // the negotiated profiles
      //
      Subject subject = null;

      // Begin Handshake
      //
      String serverProfiles = (String) env.get("jmx.remote.profiles");
      String serverVersion = "1.0";
      if (logger.traceOn()) {
    logger.trace("connectionOpen", ">>>>> Handshake Begin <<<<<");
    logger.trace("connectionOpen", "Server Supported Profiles [ " +
           serverProfiles + " ]");
    logger.trace("connectionOpen", "Server JMXMP Version [ " +
           serverVersion + " ]");
      }
      HandshakeBeginMessage begin =
    new HandshakeBeginMessage(serverProfiles, serverVersion);
      mc.writeMessage(begin);

      while (true) {
    Message msg = mc.readMessage();
    if (msg instanceof HandshakeErrorMessage) {
        // Throw exception and let GenericConnectorServer
        // close the connection
        //
        sendError = false;
        HandshakeErrorMessage error = (HandshakeErrorMessage) msg;
        AdminClient.throwExceptionOnError(error);
    } else if (msg instanceof HandshakeEndMessage) {
        HandshakeEndMessage cend = (HandshakeEndMessage) msg;
        Object ccontext = cend.getContext();
        if (logger.traceOn()) {
      logger.trace("connectionOpen",
             ">>>>> Handshake End <<<<<");
      logger.trace("connectionOpen",
             "Client Context Object [ " +
             ccontext + " ]");
        }
        Object scontext = (Object) env.get("jmx.remote.context");
        // If MessageConnection is an instance of SocketConnectionIf
        // then set the authenticated subject.
        if (mc instanceof SocketConnectionIf) {
      ((SocketConnectionIf)mc).setSubject(subject);
        }
        String connectionId = mc.getConnectionId();
        // If the environment includes an authenticator, check
        // that it accepts the connection id, and replace the
        // Subject by whatever it returns.
        JMXAuthenticator authenticator =
      (JMXAuthenticator) env.get("jmx.remote.authenticator");
        if (authenticator != null) {
      Object[] credentials = {connectionId, subject};
      subject = authenticator.authenticate(credentials);
      if (mc instanceof SocketConnectionIf) {
          ((SocketConnectionIf)mc).setSubject(subject);
      }
      connectionId = mc.getConnectionId();
        }
        if (logger.traceOn()) {
      logger.trace("connectionOpen",
             "Server Context Object [ " +
             scontext + " ]");
      logger.trace("connectionOpen",
             "Server Connection Id [ " +
             connectionId + " ]");
        }

        // Check that the negotiated profiles are acceptable for
        // the server's defined security policy. This method is
        // called just before the initial handshake is completed
        // with a HandshakeEndMessage sent from the server to the
        // client. If the method throws an exception, then a
        // HandshakeErrorMessage will be sent instead.
        //
        List profileNames = getProfilesByName(mc);
        CheckProfiles np = (CheckProfiles)
      env.get("com.sun.jmx.remote.profile.checker");
        if (np != null) {
      np.checkProfiles(env,
           profileNames,
           ccontext,
           connectionId);
        } else {
      checkProfilesForEquality(serverProfiles,
             profileNames);
        }

        HandshakeEndMessage send =
      new HandshakeEndMessage(scontext, connectionId);
        mc.writeMessage(send);
        break;
    } else if (msg instanceof VersionMessage) {
        VersionMessage cjmxmp = (VersionMessage) msg;
        String clientVersion = cjmxmp.getVersion();
        if (clientVersion.equals(serverVersion)) {
      VersionMessage sjmxmp =
          new VersionMessage(serverVersion);
      mc.writeMessage(sjmxmp);
        } else {
      throw new IOException("Protocol version " +
                "mismatch: Client [" +
                clientVersion +
                "] vs. Server [" +
                serverVersion + "]");
        }
    } else if (msg instanceof ProfileMessage) {
        ProfileMessage pm = (ProfileMessage) msg;
        String pn = pm.getProfileName();
        ProfileServer p = (ProfileServer) getProfile(mc, pn);
        if (p == null) {
      p = ProfileServerFactory.createProfile(pn, env);
      if (logger.traceOn()) {
          logger.trace("connectionOpen",
           ">>>>> Profile " +
           p.getClass().getName() +
           " <<<<<");
      }
      p.initialize(mc, subject);
      putProfile(mc, p);
        }
        p.consumeMessage(pm);
        pm = p.produceMessage();
        mc.writeMessage(pm);
        if (p.isComplete()) {
      subject = p.activate();
        }
    } else {
        throw new IOException("Unexpected message: " +
            msg.getClass().getName());
    }
      }
      putSubject(mc, subject);
  } catch (Exception e) {
      if (sendError) {
                try {
                    mc.writeMessage(new HandshakeErrorMessage(e.toString()));
                } catch (Exception hsem) {
                    if (logger.debugOn()) {
                        logger.debug(
                           "connectionOpen",
                           "Could not send HandshakeErrorMessage to the client",
                           hsem);
                    }
                }
      }
      if (e instanceof RuntimeException) {
    throw (RuntimeException) e;
      } else if (e instanceof IOException) {
    throw (IOException) e;
      } else {
    throw new IOException(e.getMessage());
      }
  }

  return mc;
    }

    public void connectionClosed(MessageConnection mc) {
  removeSubject(mc);
  removeProfiles(mc);
    }

    public Subject getSubject(MessageConnection mc) {
  synchronized (subjectsTable) {
      return (Subject) subjectsTable.get(mc);
  }
    }

    private void putSubject(MessageConnection mc, Subject s) {
  synchronized (subjectsTable) {
      subjectsTable.put(mc, s);
  }
    }

    private void removeSubject(MessageConnection mc) {
  synchronized (subjectsTable) {
      subjectsTable.remove(mc);
  }
    }

    private ProfileServer getProfile(MessageConnection mc, String pn) {
  synchronized (profilesTable) {
      ArrayList list = (ArrayList) profilesTable.get(mc);
      if (list == null) {
    return null;
      }
      for (Iterator i = list.iterator(); i.hasNext(); ) {
    ProfileServer p = (ProfileServer) i.next();
    if (p.getName().equals(pn)) {
        return p;
    }
      }
      return null;
  }
    }

    private synchronized void putProfile(MessageConnection mc,
           ProfileServer p) {
  synchronized (profilesTable) {
      ArrayList list = (ArrayList) profilesTable.get(mc);
      if (list == null) {
    list = new ArrayList();
    profilesTable.put(mc, list);
      }
      if (!list.contains(p)) {
    list.add(p);
      }
  }
    }

    private ArrayList getProfiles(MessageConnection mc) {
  synchronized (profilesTable) {
      return (ArrayList) profilesTable.get(mc);
  }
    }

    private ArrayList getProfilesByName(MessageConnection mc) {
  ArrayList profiles = getProfiles(mc);
  if (profiles == null)
      return null;
  ArrayList profileNames = new ArrayList(profiles.size());
  for (Iterator i = profiles.iterator(); i.hasNext(); ) {
      ProfileServer p = (ProfileServer) i.next();
      profileNames.add(p.getName());
  }
  return profileNames;
    }

    private synchronized void removeProfiles(MessageConnection mc) {
  synchronized (profilesTable) {
      ArrayList list = (ArrayList) profilesTable.get(mc);
      if (list != null) {
    for (Iterator i = list.iterator(); i.hasNext(); ) {
        ProfileServer p = (ProfileServer) i.next();
        try {
      p.terminate();
        } catch (Exception e) {
      if (logger.debugOn()) {
          logger.debug("removeProfiles",
            "Got an exception to terminate a ProfileServer: "+p.getName(), e);
      }
        }
    }
    list.clear();
      }
      profilesTable.remove(mc);
  }
    }

    private void checkProfilesForEquality(String serverProfiles,
            List clientProfilesList)
  throws IOException {

  // Check for null values. Both the server and the client
  // environment maps did not specified any profile.
  //
  boolean serverFlag =
      (serverProfiles == null || serverProfiles.equals(""));

  boolean clientFlag =
      (clientProfilesList == null || clientProfilesList.isEmpty());

  if (serverFlag && clientFlag)
      return;

  if (serverFlag)
      throw new IOException("The server does not support any " +
          "profile but the client requires one");

  if (clientFlag)
      throw new IOException("The client does not require any " +
          "profile but the server mandates one");

  // Build ArrayList<String> from server profiles string.
  //
        StringTokenizer sst = new StringTokenizer(serverProfiles, " ");
        ArrayList serverProfilesList = new ArrayList(sst.countTokens());
        while (sst.hasMoreTokens()) {
            String serverToken = sst.nextToken();
            serverProfilesList.add(serverToken);
        }

  // Check for size equality.
  //
  if (serverProfilesList.size() != clientProfilesList.size())
      throw new IOException("The client negotiated profiles do not " +
          "match the server required profiles.");

  // Check for content equality.
  //
  if (!clientProfilesList.containsAll(serverProfilesList))
      throw new IOException("The client negotiated profiles " +
          clientProfilesList + " do not match " +
          "the server required profiles " +
          serverProfilesList + ".");
    }

    private Map env = null;
    private Map subjectsTable = new WeakHashMap();
    private Map profilesTable = new WeakHashMap();
    private static final ClassLogger logger =
  new ClassLogger("javax.management.remote.misc", "AdminServer");
}
TOP

Related Classes of com.sun.jmx.remote.opt.security.AdminServer

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.