All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.helger.as2.cmdprocessor.SocketCommandProcessor Maven / Gradle / Ivy

There is a newer version: 5.1.3
Show newest version
/*
 * The FreeBSD Copyright
 * Copyright 1994-2008 The FreeBSD Project. All rights reserved.
 * Copyright (C) 2013-2023 Philip Helger philip[at]helger[dot]com
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *    1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 *    2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * The views and conclusions contained in the software and documentation
 * are those of the authors and should not be interpreted as representing
 * official policies, either expressed or implied, of the FreeBSD Project.
 */
package com.helger.as2.cmdprocessor;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.helger.as2.cmd.CommandResult;
import com.helger.as2.cmd.ICommand;
import com.helger.as2.util.CommandTokenizer;
import com.helger.as2lib.CAS2Info;
import com.helger.as2lib.exception.AS2Exception;
import com.helger.as2lib.exception.WrappedAS2Exception;
import com.helger.as2lib.session.IAS2Session;
import com.helger.commons.annotation.OverrideOnDemand;
import com.helger.commons.collection.attr.IStringMap;
import com.helger.commons.collection.attr.StringMap;
import com.helger.commons.collection.impl.CommonsArrayList;
import com.helger.commons.collection.impl.CommonsLinkedHashSet;
import com.helger.commons.collection.impl.ICommonsList;
import com.helger.commons.collection.impl.ICommonsOrderedSet;
import com.helger.commons.io.stream.NonBlockingBufferedReader;
import com.helger.commons.io.stream.NonBlockingBufferedWriter;
import com.helger.commons.string.StringHelper;

/**
 * actual socket command processor takes commands from socket/port and passes
 * them to the OpenAS2Server message format <command userid="abc"
 * pasword="xyz">the actual command</command> when inited the valid
 * userid and password is passed, then as each command is processed the
 * processCommand method verifies the two fields correctness
 *
 * @author joseph mcverry
 */
public class SocketCommandProcessor extends AbstractCommandProcessor
{
  public static final String ATTR_PORTID = "portid";
  public static final String ATTR_USERID = "userid";
  public static final String ATTR_PASSWORD = "password";

  private static final Logger LOGGER = LoggerFactory.getLogger (SocketCommandProcessor.class);

  private NonBlockingBufferedReader m_aReader;
  private NonBlockingBufferedWriter m_aWriter;
  private SSLServerSocket m_aSSLServerSocket;

  private String m_sUserID;
  private String m_sPassword;
  private SocketCommandParser m_aParser;

  public SocketCommandProcessor ()
  {}

  @OverrideOnDemand
  @Nullable
  protected String [] getEnabledAnonymousCipherSuites (@Nonnull final String [] aEnabled, @Nonnull final String [] aSupported)
  {
    final ICommonsOrderedSet  ret = new CommonsLinkedHashSet <> ();
    for (final String sSupported : aSupported)
    {
      // No SSL - usually TLS
      // Only anonymous
      // No DES
      // No MD5
      if (!sSupported.startsWith ("SSL") &&
          sSupported.indexOf ("_anon_") >= 0 &&
          (sSupported.indexOf ("_AES_") >= 0 || sSupported.indexOf ("_3DES_") >= 0) &&
          sSupported.indexOf ("_SHA") >= 0)
      {
        ret.add (sSupported);
      }
    }
    ret.addAll (aEnabled);
    return ret.toArray (new String [0]);
  }

  @Override
  public void initDynamicComponent (@Nonnull final IAS2Session aSession, @Nullable final IStringMap aParams) throws AS2Exception
  {
    final StringMap aParameters = aParams == null ? new StringMap () : new StringMap (aParams);
    final String sPort = aParameters.getAsString (ATTR_PORTID);
    try
    {
      final int nPort = Integer.parseInt (sPort);

      final SSLServerSocketFactory aSSLServerSocketFactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault ();
      m_aSSLServerSocket = (SSLServerSocket) aSSLServerSocketFactory.createServerSocket (nPort);
      final String [] aEnabledCipherSuites = getEnabledAnonymousCipherSuites (m_aSSLServerSocket.getEnabledCipherSuites (),
                                                                              m_aSSLServerSocket.getSupportedCipherSuites ());
      m_aSSLServerSocket.setEnabledCipherSuites (aEnabledCipherSuites);
    }
    catch (final IOException e)
    {
      throw new AS2Exception (e);
    }
    catch (final NumberFormatException e)
    {
      throw new AS2Exception ("Error converting portid parameter '" + sPort + "': " + e);
    }

    m_sUserID = aParameters.getAsString (ATTR_USERID);
    if (StringHelper.hasNoText (m_sUserID))
      throw new AS2Exception ("missing 'userid' parameter");

    m_sPassword = aParameters.getAsString (ATTR_PASSWORD);
    if (StringHelper.hasNoText (m_sPassword))
      throw new AS2Exception ("missing 'password' parameter");

    try
    {
      m_aParser = new SocketCommandParser ();
    }
    catch (final Exception e)
    {
      throw new AS2Exception (e);
    }
  }

  @Override
  public void processCommand () throws AS2Exception
  {
    try (final SSLSocket socket = (SSLSocket) m_aSSLServerSocket.accept ())
    {
      socket.setSoTimeout (2000);
      m_aReader = new NonBlockingBufferedReader (new InputStreamReader (socket.getInputStream ()));
      m_aWriter = new NonBlockingBufferedWriter (new OutputStreamWriter (socket.getOutputStream ()));

      final String line = m_aReader.readLine ();

      m_aParser.parse (line);

      if (!m_aParser.getUserid ().equals (m_sUserID))
      {
        m_aWriter.write ("Bad userid/password");
        throw new AS2Exception ("Bad userid");
      }

      if (!m_aParser.getPassword ().equals (m_sPassword))
      {
        m_aWriter.write ("Bad userid/password");
        throw new AS2Exception ("Bad password");
      }

      final String str = m_aParser.getCommandText ();
      if (str != null && str.length () > 0)
      {
        final CommandTokenizer cmdTkn = new CommandTokenizer (str);

        if (cmdTkn.hasMoreTokens ())
        {
          final String sCommandName = cmdTkn.nextToken ().toLowerCase ();

          if (sCommandName.equals (StreamCommandProcessor.EXIT_COMMAND))
          {
            terminate ();
          }
          else
          {
            final ICommonsList  params = new CommonsArrayList <> ();

            while (cmdTkn.hasMoreTokens ())
            {
              params.add (cmdTkn.nextToken ());
            }

            final ICommand aCommand = getCommand (sCommandName);
            if (aCommand != null)
            {
              final CommandResult aResult = aCommand.execute (params.toArray ());

              if (aResult.getType ().isSuccess ())
              {
                m_aWriter.write (aResult.getAsXMLString ());
              }
              else
              {
                m_aWriter.write ("\r\n" + StreamCommandProcessor.COMMAND_ERROR + "\r\n");
                m_aWriter.write (aResult.getResultAsString ());
              }
            }
            else
            {
              m_aWriter.write (StreamCommandProcessor.COMMAND_NOT_FOUND + "> " + sCommandName + "\r\n");
              m_aWriter.write ("List of commands:" + "\r\n");
              for (final String sCurCmd : getAllCommands ().keySet ())
                m_aWriter.write (sCurCmd + "\r\n");
            }
          }
        }

      }
      m_aWriter.flush ();
    }
    catch (final IOException ex)
    {
      throw WrappedAS2Exception.wrap (ex);
    }
  }

  @Override
  public void run ()
  {
    try
    {
      while (true)
        processCommand ();
    }
    catch (final AS2Exception ex)
    {
      LOGGER.error ("Error running command processor " + CAS2Info.NAME_VERSION, ex);
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy