|
What this is
Other links
The source code/* * Copyright 1999-2004 The Apache Software Foundation * * Licensed 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 org.apache.ajp; import java.io.IOException; import java.security.MessageDigest; import org.apache.tomcat.util.buf.HexUtils; import org.apache.tomcat.util.http.BaseRequest; /** * Handler for the protocol negotiation. It will authenticate and * exchange information about supported messages on each end. * * * @author Henri Gomez [hgomez@apache.org] * @author Dan Milstein [danmil@shore.net] * @author Keith Wannamaker [Keith@Wannamaker.org] * @author Costin Manolache */ public class NegociationHandler extends AjpHandler { // Initial Login Phase (web server -> servlet engine) public static final byte JK_AJP14_LOGINIT_CMD=0x10; // Second Login Phase (servlet engine -> web server), md5 seed is received public static final byte JK_AJP14_LOGSEED_CMD=0x11; // Third Login Phase (web server -> servlet engine), // md5 of seed + secret is sent public static final byte JK_AJP14_LOGCOMP_CMD=0x12; // Login Accepted (servlet engine -> web server) public static final byte JK_AJP14_LOGOK_CMD=0x13; // Login Rejected (servlet engine -> web server), will be logged public static final byte JK_AJP14_LOGNOK_CMD=0x14; // Context Query (web server -> servlet engine), // which URI are handled by servlet engine ? public static final byte JK_AJP14_CONTEXT_QRY_CMD=0x15; // Context Info (servlet engine -> web server), URI handled response public static final byte JK_AJP14_CONTEXT_INFO_CMD= 0x16; // Context Update (servlet engine -> web server), status of context changed public static final byte JK_AJP14_CONTEXT_UPDATE_CMD= 0x17; // Servlet Engine Status (web server -> servlet engine), // what's the status of the servlet engine ? public static final byte JK_AJP14_STATUS_CMD= 0x18; // Secure Shutdown command (web server -> servlet engine), //please servlet stop yourself. public static final byte JK_AJP14_SHUTDOWN_CMD= 0x19; // Secure Shutdown command Accepted (servlet engine -> web server) public static final byte JK_AJP14_SHUTOK_CMD= 0x1A; // Secure Shutdown Rejected (servlet engine -> web server) public static final byte JK_AJP14_SHUTNOK_CMD= 0x1B; // Context Status (web server -> servlet engine), //what's the status of the context ? public static final byte JK_AJP14_CONTEXT_STATE_CMD= 0x1C; // Context Status Reply (servlet engine -> web server), status of context public static final byte JK_AJP14_CONTEXT_STATE_REP_CMD = 0x1D; // Unknown Packet Reply (web server <-> servlet engine), //when a packet couldn't be decoded public static final byte JK_AJP14_UNKNOW_PACKET_CMD = 0x1E; // -------------------- Other constants -------------------- // Entropy Packet Size public static final int AJP14_ENTROPY_SEED_LEN= 32; public static final int AJP14_COMPUTED_KEY_LEN= 32; // web-server want context info after login public static final int AJP14_CONTEXT_INFO_NEG= 0x80000000; // web-server want context updates public static final int AJP14_CONTEXT_UPDATE_NEG= 0x40000000; // web-server want compressed stream public static final int AJP14_GZIP_STREAM_NEG= 0x20000000; // web-server want crypted DES56 stream with secret key public static final int AJP14_DES56_STREAM_NEG= 0x10000000; // Extended info on server SSL vars public static final int AJP14_SSL_VSERVER_NEG= 0x08000000; // Extended info on client SSL vars public static final int AJP14_SSL_VCLIENT_NEG= 0x04000000; // Extended info on crypto SSL vars public static final int AJP14_SSL_VCRYPTO_NEG= 0x02000000; // Extended info on misc SSL vars public static final int AJP14_SSL_VMISC_NEG= 0x01000000; // mask of protocol supported public static final int AJP14_PROTO_SUPPORT_AJPXX_NEG=0x00FF0000; // communication could use AJP14 public static final int AJP14_PROTO_SUPPORT_AJP14_NEG=0x00010000; // communication could use AJP15 public static final int AJP14_PROTO_SUPPORT_AJP15_NEG=0x00020000; // communication could use AJP16 public static final int AJP14_PROTO_SUPPORT_AJP16_NEG=0x00040000; // Some failure codes public static final int AJP14_BAD_KEY_ERR= 0xFFFFFFFF; public static final int AJP14_ENGINE_DOWN_ERR = 0xFFFFFFFE; public static final int AJP14_RETRY_LATER_ERR = 0xFFFFFFFD; public static final int AJP14_SHUT_AUTHOR_FAILED_ERR = 0xFFFFFFFC; // Some status codes public static final byte AJP14_CONTEXT_DOWN= 0x01; public static final byte AJP14_CONTEXT_UP= 0x02; public static final byte AJP14_CONTEXT_OK= 0x03; // -------------------- Parameters -------------------- String containerSignature="Ajp14-based container"; String seed="seed";// will use random String password; int webserverNegociation=0; // String webserverName; public NegociationHandler() { setSeed("myveryrandomentropy"); setPassword("myverysecretkey"); } public void setContainerSignature( String s ) { containerSignature=s; } // -------------------- State -------------------- // public String getWebserverName() { // return webserverName; // } // -------------------- Parameters -------------------- /** * Set the original entropy seed */ public void setSeed(String pseed) { String[] credentials = new String[1]; credentials[0] = pseed; seed = digest(credentials, "md5"); } /** * Get the original entropy seed */ public String getSeed() { return seed; } /** * Set the secret password */ public void setPassword(String ppwd) { password = ppwd; } /** * Get the secret password */ public String getPassword() { return password; } // -------------------- Initialization -------------------- public void init( Ajp13 ajp14 ) { super.init(ajp14); // register incoming message handlers ajp14.registerMessageType( JK_AJP14_LOGINIT_CMD,"JK_AJP14_LOGINIT_CMD", this, null); // ajp14.registerMessageType( JK_AJP14_LOGCOMP_CMD,"JK_AJP14_LOGCOMP_CMD", this, null); // ajp14.registerMessageType( RequestHandler.JK_AJP13_SHUTDOWN,"JK_AJP13_SHUTDOWN", this, null); // ajp14.registerMessageType( JK_AJP14_CONTEXT_QRY_CMD, "JK_AJP14_CONTEXT_QRY_CMD", this, null); // ajp14.registerMessageType( JK_AJP14_STATUS_CMD,"JK_AJP14_STATUS_CMD", this, null); // ajp14.registerMessageType( JK_AJP14_SHUTDOWN_CMD, "JK_AJP14_SHUTDOWN_CMD", this, null); // ajp14.registerMessageType( JK_AJP14_CONTEXT_STATE_CMD, "JK_AJP14_CONTEXT_STATE_CMD", this, null); // ajp14.registerMessageType( JK_AJP14_UNKNOW_PACKET_CMD, "JK_AJP14_UNKNOW_PACKET_CMD", this, null); // // register outgoing messages handler ajp14.registerMessageType( JK_AJP14_LOGNOK_CMD,"JK_AJP14_LOGNOK_CMD", this,null ); } // -------------------- Dispatch -------------------- public int handleAjpMessage( int type, Ajp13 ch, Ajp13Packet hBuf, BaseRequest req ) throws IOException { System.out.println("handleAjpMessage: " + type ); Ajp13Packet outBuf=ch.outBuf; // Valid requests when not logged: switch( type ) { case JK_AJP14_LOGINIT_CMD : return handleLogInit(ch, hBuf, outBuf); case JK_AJP14_LOGCOMP_CMD : return handleLogComp(ch, hBuf, outBuf); case RequestHandler.JK_AJP13_SHUTDOWN: return -2; case JK_AJP14_CONTEXT_QRY_CMD : return handleContextQuery(ch, hBuf, outBuf); case JK_AJP14_STATUS_CMD : return handleStatus(hBuf, outBuf); case JK_AJP14_SHUTDOWN_CMD : return handleShutdown(hBuf, outBuf); case JK_AJP14_CONTEXT_STATE_CMD : return handleContextState(hBuf, outBuf); case JK_AJP14_UNKNOW_PACKET_CMD : return handleUnknowPacket(hBuf, outBuf); default: log("unknown command " + type + " received"); return 200; // XXX This is actually an error condition } //return UNKNOWN; } //----------- Implementation for various protocol commands ----------- /** * Handle the Initial Login Message from Web-Server * * Get the requested Negociation Flags * Get also the Web-Server Name * * Send Login Seed (MD5 of seed) */ private int handleLogInit( Ajp13 ch, Ajp13Packet msg, Ajp13Packet outBuf ) throws IOException { webserverNegociation = msg.getLongInt(); String webserverName = msg.getString(); log("in handleLogInit with nego " + decodeNegociation(webserverNegociation) + " from webserver " + webserverName); outBuf.reset(); outBuf.appendByte(JK_AJP14_LOGSEED_CMD); String[] credentials = new String[1]; credentials[0] = getSeed(); outBuf.appendXBytes(getSeed().getBytes(), 0, AJP14_ENTROPY_SEED_LEN); log("in handleLogInit: sent entropy " + getSeed()); outBuf.end(); ch.send(outBuf); return 304; } /** * Handle the Second Phase of Login (accreditation) * * Get the MD5 digest of entropy + secret password * If the authentification is valid send back LogOk * If the authentification failed send back LogNok */ private int handleLogComp( Ajp13 ch, Ajp13Packet msg, Ajp13Packet outBuf ) throws IOException { // log("in handleLogComp :"); byte [] rdigest = new byte[AJP14_ENTROPY_SEED_LEN]; if (msg.getXBytes(rdigest, AJP14_ENTROPY_SEED_LEN) < 0) return 200; String[] credentials = new String[2]; credentials[0] = getSeed(); credentials[1] = getPassword(); String computed = digest(credentials, "md5"); String received = new String(rdigest); // XXX temp workaround, to test the rest of the connector. if ( ! computed.equalsIgnoreCase(received)) { log("in handleLogComp : authentification failure received=" + received + " awaited=" + computed); } if (false ) { // ! computed.equalsIgnoreCase(received)) { log("in handleLogComp : authentification failure received=" + received + " awaited=" + computed); // we should have here a security mecanism which could maintain // a list of remote IP which failed too many times // so we could reject them quickly at next connect outBuf.reset(); outBuf.appendByte(JK_AJP14_LOGNOK_CMD); outBuf.appendLongInt(AJP14_BAD_KEY_ERR); outBuf.end(); ch.send(outBuf); return 200; } else { // logged we can go process requests channel.setLogged(true); outBuf.reset(); outBuf.appendByte(JK_AJP14_LOGOK_CMD); outBuf.appendLongInt(getProtocolFlags(webserverNegociation)); outBuf.appendString( containerSignature ); outBuf.end(); ch.send(outBuf); } return (304); } private int handleContextQuery( Ajp13 ch, Ajp13Packet msg, Ajp13Packet outBuf ) throws IOException { log("in handleContextQuery :"); String virtualHost = msg.getString(); log("in handleContextQuery for virtual" + virtualHost); outBuf.reset(); outBuf.appendByte(JK_AJP14_CONTEXT_INFO_CMD); outBuf.appendString( virtualHost ); log("in handleContextQuery for virtual " + virtualHost + "examples URI/MIMES"); outBuf.appendString("examples"); // first context - examples outBuf.appendString("servlet/*"); // examples/servlet/* outBuf.appendString("*.jsp"); // examples/*.jsp outBuf.appendString(""); // no more URI/MIMES log("in handleContextQuery for virtual " + virtualHost + "send admin URI/MIMES"); outBuf.appendString("admin"); // second context - admin outBuf.appendString("servlet/*"); // /admin//servlet/* outBuf.appendString("*.jsp"); // /admin/*.jsp outBuf.appendString(""); // no more URI/MIMES outBuf.appendString(""); // no more contexts outBuf.end(); ch.send(outBuf); return (304); } private int handleStatus( Ajp13Packet msg, Ajp13Packet outBuf ) throws IOException { log("in handleStatus :"); return (304); } private int handleShutdown( Ajp13Packet msg, Ajp13Packet outBuf ) throws IOException { log("in handleShutdown :"); return (304); } private int handleContextState( Ajp13Packet msg , Ajp13Packet outBuf) throws IOException { log("in handleContextState :"); return (304); } private int handleUnknowPacket( Ajp13Packet msg, Ajp13Packet outBuf ) throws IOException { log("in handleUnknowPacket :"); return (304); } // -------------------- Utils -------------------- /** * Compute the Protocol Negociation Flags * * Depending the protocol fatures implemented on servet-engine, * we'll drop requested features which could be asked by web-server * * Hopefully this functions could be overrided by decendants */ private int getProtocolFlags(int wanted) { // no real-time context update wanted &= ~(AJP14_CONTEXT_UPDATE_NEG | // no gzip compression yet AJP14_GZIP_STREAM_NEG | // no DES56 cyphering yet AJP14_DES56_STREAM_NEG | // no Extended info on server SSL vars yet AJP14_SSL_VSERVER_NEG | // no Extended info on client SSL vars yet AJP14_SSL_VCLIENT_NEG | // no Extended info on crypto SSL vars yet AJP14_SSL_VCRYPTO_NEG | // no Extended info on misc SSL vars yet AJP14_SSL_VMISC_NEG | // Reset AJP protocol mask AJP14_PROTO_SUPPORT_AJPXX_NEG); // Only strict AJP14 supported return (wanted | AJP14_PROTO_SUPPORT_AJP14_NEG); } /** * Compute a digest (MD5 in AJP14) for an array of String */ public final String digest(String[] credentials, String algorithm) { try { // Obtain a new message digest with MD5 encryption MessageDigest md = (MessageDigest)MessageDigest.getInstance(algorithm).clone(); // encode the credentials items for (int i = 0; i < credentials.length; i++) { if( debug > 0 ) log("Credentials : " + i + " " + credentials[i]); if( credentials[i] != null ) md.update(credentials[i].getBytes()); } // obtain the byte array from the digest byte[] dig = md.digest(); return HexUtils.convert(dig); } catch (Exception ex) { ex.printStackTrace(); return null; } } // -------------------- Debugging -------------------- // Very usefull for develoment /** * Display Negociation field in human form */ private String decodeNegociation(int nego) { StringBuffer buf = new StringBuffer(128); if ((nego & AJP14_CONTEXT_INFO_NEG) != 0) buf.append(" CONTEXT-INFO"); if ((nego & AJP14_CONTEXT_UPDATE_NEG) != 0) buf.append(" CONTEXT-UPDATE"); if ((nego & AJP14_GZIP_STREAM_NEG) != 0) buf.append(" GZIP-STREAM"); if ((nego & AJP14_DES56_STREAM_NEG) != 0) buf.append(" DES56-STREAM"); if ((nego & AJP14_SSL_VSERVER_NEG) != 0) buf.append(" SSL-VSERVER"); if ((nego & AJP14_SSL_VCLIENT_NEG) != 0) buf.append(" SSL-VCLIENT"); if ((nego & AJP14_SSL_VCRYPTO_NEG) != 0) buf.append(" SSL-VCRYPTO"); if ((nego & AJP14_SSL_VMISC_NEG) != 0) buf.append(" SSL-VMISC"); if ((nego & AJP14_PROTO_SUPPORT_AJP14_NEG) != 0) buf.append(" AJP14"); if ((nego & AJP14_PROTO_SUPPORT_AJP15_NEG) != 0) buf.append(" AJP15"); if ((nego & AJP14_PROTO_SUPPORT_AJP16_NEG) != 0) buf.append(" AJP16"); return (buf.toString()); } private static int debug=10; void log(String s) { System.out.println("Ajp14Negotiation: " + s ); } } |
... this post is sponsored by my books ... | |
![]() #1 New Release! |
![]() FP Best Seller |
Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.