You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by hb...@apache.org on 2001/11/23 19:55:02 UTC
cvs commit: jakarta-james/proposal/sasl/src/org/apache/james/smtpserver SMTPHandler.java SaslProfile.java
hbedi 01/11/23 10:55:02
Added: proposal/sasl/src/org/apache/james/smtpserver
SMTPHandler.java SaslProfile.java
Log:
Cryptix SASL plugin by Keith <ke...@rucus.ru.ac.za>
Revision Changes Path
1.1 jakarta-james/proposal/sasl/src/org/apache/james/smtpserver/SMTPHandler.java
Index: SMTPHandler.java
===================================================================
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.james.smtpserver;
import java.io.*;
import java.net.*;
import java.util.*;
import javax.mail.*;
import javax.mail.internet.*;
import org.apache.avalon.framework.activity.Initializable;
import org.apache.avalon.framework.component.ComponentException;
import org.apache.avalon.framework.component.ComponentManager;
import org.apache.avalon.framework.component.Composable;
import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.context.Context;
import org.apache.avalon.framework.context.ContextException;
import org.apache.avalon.framework.context.Contextualizable;
import org.apache.avalon.framework.logger.AbstractLoggable;
import org.apache.avalon.cornerstone.services.connection.ConnectionHandler;
import org.apache.avalon.cornerstone.services.scheduler.PeriodicTimeTrigger;
import org.apache.avalon.cornerstone.services.scheduler.Target;
import org.apache.avalon.cornerstone.services.scheduler.TimeScheduler;
import org.apache.james.*;
import org.apache.james.core.*;
import org.apache.james.services.MailServer;
import org.apache.james.services.UsersRepository;
import org.apache.james.services.UsersStore;
import org.apache.james.util.*;
import org.apache.mailet.*;
import javax.security.sasl.*;
/**
* This handles an individual incoming message. It handles regular SMTP
* commands, and when it receives a message, adds it to the spool.
* @author Serge Knystautas <se...@lokitech.com>
* @author Federico Barbieri <sc...@systemy.it>
* @author Jason Borden <jb...@javasense.com>
* @author Matthew Pangaro <ma...@lokitech.com>
*
* This is $Revision: 1.1 $
* Committed on $Date: 2001/11/23 18:55:01 $ by: $Author: hbedi $
*/
public class SMTPHandler
extends BaseConnectionHandler
implements ConnectionHandler, Composable, Configurable, Target {
public final static String SERVER_NAME = "SERVER_NAME";
public final static String SERVER_TYPE = "SERVER_TYPE";
public final static String REMOTE_NAME = "REMOTE_NAME";
public final static String REMOTE_IP = "REMOTE_IP";
public final static String NAME_GIVEN = "NAME_GIVEN";
public final static String CURRENT_HELO_MODE = "CURRENT_HELO_MODE";
public final static String SENDER = "SENDER_ADDRESS";
public final static String MESG_FAILED = "MESG_FAILED";
public final static String RCPT_VECTOR = "RCPT_VECTOR";
public final static String SMTP_ID = "SMTP_ID";
public final static String AUTH = "AUTHENTICATED";
public final static char[] SMTPTerminator = {'\r','\n','.','\r','\n'};
private final static boolean DEEP_DEBUG = true;
private Socket socket;
private DataInputStream in;
private PrintWriter out;
private String remoteHost;
private String remoteHostGiven;
private String remoteIP;
private String messageID;
private String smtpID;
private boolean authRequired = false;
private boolean verifyIdentity = false;
private TimeScheduler scheduler;
private UsersRepository users;
private MailServer mailServer;
private String softwaretype = "JAMES SMTP Server "
+ Constants.SOFTWARE_VERSION;
private static long count;
private HashMap state = new HashMap();
private Random random = new Random();
private long maxmessagesize = 0;
private static SaslServerFactory serverFactory = new cryptix.sasl.ServerFactory();
public void configure ( Configuration configuration )
throws ConfigurationException {
super.configure(configuration);
authRequired
= configuration.getChild("authRequired").getValueAsBoolean(true);
verifyIdentity
= configuration.getChild("verifyIdentity").getValueAsBoolean(false);
// get the message size limit from the conf file and multiply
// by 1024, to put it in bytes
maxmessagesize =
configuration.getChild( "maxmessagesize" ).getValueAsLong( 0 ) * 1024;
if (DEEP_DEBUG) {
getLogger().debug("Max message size is: " + maxmessagesize);
}
Sasl.setSaslServerFactory(serverFactory);
}
public void compose( final ComponentManager componentManager )
throws ComponentException {
mailServer = (MailServer)componentManager.lookup(
"org.apache.james.services.MailServer");
scheduler = (TimeScheduler)componentManager.lookup(
"org.apache.avalon.cornerstone.services.scheduler.TimeScheduler");
UsersStore usersStore = (UsersStore)componentManager.lookup(
"org.apache.james.services.UsersStore" );
users = usersStore.getRepository("LocalUsers");
}
/**
* Handle a connection.
* This handler is responsible for processing connections as they occur.
*
* @param connection the connection
* @exception IOException if an error reading from socket occurs
* @exception ProtocolException if an error handling connection occurs
*/
public void handleConnection( Socket connection )
throws IOException {
try {
this.socket = connection;
final InputStream bufferedInput =
new BufferedInputStream( socket.getInputStream(), 1024 );
in = new DataInputStream( bufferedInput );
out = new InternetPrintWriter(socket.getOutputStream(), true);
remoteHost = socket.getInetAddress ().getHostName ();
remoteIP = socket.getInetAddress ().getHostAddress ();
smtpID = Math.abs(random.nextInt() % 1024) + "";
resetState();
} catch (Exception e) {
getLogger().error("Cannot open connection from " + remoteHost
+ " (" + remoteIP + "): " + e.getMessage(), e );
throw new RuntimeException("Cannot open connection from "
+ remoteHost + " (" + remoteIP + "): " + e.getMessage());
}
getLogger().info("Connection from " + remoteHost + " ("
+ remoteIP + ")");
try {
// Initially greet the connector
// Format is: Sat, 24 Jan 1998 13:16:09 -0500
final PeriodicTimeTrigger trigger
= new PeriodicTimeTrigger( timeout, -1 );
scheduler.addTrigger( this.toString(), trigger, this );
out.println("220 " + this.helloName + " SMTP Server ("
+ softwaretype + ") ready "
+ RFC822DateFormat.toString(new Date()));
while (parseCommand(in.readLine())) {
scheduler.resetTrigger(this.toString());
}
socket.close();
scheduler.removeTrigger(this.toString());
} catch (SocketException se) {
getLogger().debug("Socket to " + remoteHost
+ " closed remotely.", se );
} catch ( InterruptedIOException iioe ) {
getLogger().debug( "Socket to " + remoteHost + " timeout.", iioe );
} catch ( IOException ioe ) {
getLogger().debug( "Exception handling socket to " + remoteHost
+ ":" + ioe.getMessage(), ioe );
} catch (Exception e) {
getLogger().debug( "Exception opening socket: "
+ e.getMessage(), e );
} finally {
try {
socket.close();
} catch (IOException e) {
getLogger().error("Exception closing socket: "
+ e.getMessage());
}
}
}
public void targetTriggered( final String triggerName ) {
getLogger().error("Connection timeout on socket");
try {
out.println("Connection timeout. Closing connection");
socket.close();
} catch (IOException e) {
}
}
private void resetState() {
state.clear();
state.put(SERVER_NAME, this.helloName );
state.put(SERVER_TYPE, this.softwaretype );
state.put(REMOTE_NAME, remoteHost);
state.put(REMOTE_IP, remoteIP);
state.put(SMTP_ID, smtpID);
}
private boolean parseCommand(String command)
throws Exception {
if (command == null) return false;
if (state.get(MESG_FAILED) == null) {
getLogger().info("Command received: " + command);
}
StringTokenizer commandLine
= new StringTokenizer(command.trim(), " :");
int arguments = commandLine.countTokens();
if (arguments == 0) {
return true;
} else if(arguments > 0) {
command = commandLine.nextToken();
}
String argument = (String) null;
if(arguments > 1) {
argument = commandLine.nextToken();
}
String argument1 = (String) null;
if(arguments > 2) {
argument1 = commandLine.nextToken();
}
if (command.equalsIgnoreCase("HELO"))
doHELO(command,argument,argument1);
else if (command.equalsIgnoreCase("EHLO"))
doEHLO(command,argument,argument1);
else if (command.equalsIgnoreCase("AUTH"))
doAUTH(command,argument,argument1);
else if (command.equalsIgnoreCase("MAIL"))
doMAIL(command,argument,argument1);
else if (command.equalsIgnoreCase("RCPT"))
doRCPT(command,argument,argument1);
else if (command.equalsIgnoreCase("NOOP"))
doNOOP(command,argument,argument1);
else if (command.equalsIgnoreCase("RSET"))
doRSET(command,argument,argument1);
else if (command.equalsIgnoreCase("DATA"))
doDATA(command,argument,argument1);
else if (command.equalsIgnoreCase("QUIT"))
doQUIT(command,argument,argument1);
else
doUnknownCmd(command,argument,argument1);
return (command.equalsIgnoreCase("QUIT") == false);
}
private void doHELO(String command,String argument,String argument1) {
if (state.containsKey(CURRENT_HELO_MODE)) {
out.println("250 " + state.get(SERVER_NAME)
+ " Duplicate HELO");
} else if (argument == null) {
out.println("501 domain address required: " + command);
} else {
state.put(CURRENT_HELO_MODE, command);
state.put(NAME_GIVEN, argument);
out.println( "250 " + state.get(SERVER_NAME) + " Hello "
+ argument + " (" + state.get(REMOTE_NAME)
+ " [" + state.get(REMOTE_IP) + "])");
}
}
private void doEHLO(String command,String argument,String argument1) {
if (state.containsKey(CURRENT_HELO_MODE)) {
out.println("250 " + state.get(SERVER_NAME)
+ " Duplicate EHLO");
} else if (argument == null) {
out.println("501 domain address required: " + command);
} else {
state.put(CURRENT_HELO_MODE, command);
state.put(NAME_GIVEN, argument);
if (authRequired) {
out.println("250-AUTH "+getAuthString());
}
if (maxmessagesize > 0) {
out.println("250-SIZE " + maxmessagesize);
}
out.println( "250 " + state.get(SERVER_NAME) + " Hello "
+ argument + " (" + state.get(REMOTE_NAME)
+ " [" + state.get(REMOTE_IP) + "])");
}
}
private String getAuthString() {
StringBuffer authString = new StringBuffer("LOGIN ");
String[] mechanisms = serverFactory.getMechanismNames(null);
if (mechanisms.length > 0) {
authString.append(mechanisms[0]);
for (int i=1;i<mechanisms.length;i++) {
authString.append(" "+mechanisms[i]);
}
}
return authString.toString();
}
private void doAUTH(String command,String argument,String argument1)
throws Exception {
String[] mechanisms = serverFactory.getMechanismNames(null);
if (state.containsKey(AUTH)) {
out.println("503 User has previously authenticated."
+ " Further authentication is not required!");
return;
} else if (argument == null) {
out.println("501 Usage: AUTH <"+getAuthString()+
"> [<initial response>]");
return;
// } else if (argument.equalsIgnoreCase("PLAIN")) {
// String userpass, user, pass;
// StringTokenizer authTokenizer;
// if (argument1 == null) {
// out.println("334 OK. Continue authentication");
// userpass = in.readLine().trim();
// } else
// userpass = argument1.trim();
// authTokenizer = new StringTokenizer(
// Base64.decodeAsString(userpass), "\0");
// user = authTokenizer.nextToken();
// pass = authTokenizer.nextToken();
// // Authenticate user
// if (users.test(user, pass)) {
// state.put(AUTH, user);
// out.println("235 Authentication Successful");
// getLogger().info("AUTH method PLAIN succeeded");
// } else {
// out.println("535 Authentication Failed");
// getLogger().error("AUTH method PLAIN failed");
// }
// return;
} else if (argument.equalsIgnoreCase("LOGIN")) {
String user, pass;
if (argument1 == null) {
out.println("334 VXNlcm5hbWU6"); // base64 encoded "Username:"
user = in.readLine().trim();
} else
user = argument1.trim();
user = Base64.decodeAsString(user);
out.println("334 UGFzc3dvcmQ6"); // base64 encoded "Password:"
pass = Base64.decodeAsString(in.readLine().trim());
//Authenticate user
if (users.test(user, pass)) {
state.put(AUTH, user);
out.println("235 Authentication Successful");
getLogger().info("AUTH method LOGIN succeeded");
} else {
out.println("535 Authentication Failed");
getLogger().error("AUTH method LOGIN failed");
}
return;
}
for (int i=0;i<mechanisms.length;i++) {
if (argument.equalsIgnoreCase(mechanisms[i])) {
java.util.Hashtable properties = new java.util.Hashtable();
properties.put("cryptix.sasl.srp.password.file","/tmp/cryptix-sasl/etc/tpasswd");
properties.put("cryptix.sasl.plain.password.file","/tmp/cryptix-sasl/etc/passwd");
SaslServer server =
Sasl.createSaslServer(mechanisms[i],
"SMTP",
(String)state.get(SERVER_NAME),
properties,
null);
SaslProfile profile = new SaslProfile(server, in, out);
if (profile.doAUTH(argument1)) {
state.put(AUTH, server.getAuthorizationID());
out.println("235 Authentication Successful");
getLogger().info("AUTH method "+mechanisms[i]+" succeeded");
} else {
out.println("535 Authentication Failed");
getLogger().error("AUTH method "+mechanisms[i]+" failed");
}
return;
}
}
out.println("504 Unrecognized Authentication Type");
getLogger().error("AUTH method " + argument
+ " is an unrecognized authentication type");
return;
}
private void doMAIL(String command,String argument,String argument1) {
if (state.containsKey(SENDER)) {
out.println("503 Sender already specified");
} else if (argument == null || !argument.equalsIgnoreCase("FROM")
|| argument1 == null) {
out.println("501 Usage: MAIL FROM:<sender>");
} else {
String sender = argument1.trim();
if (!sender.startsWith("<") || !sender.endsWith(">")) {
out.println("501 Syntax error in parameters or arguments");
getLogger().error("Error parsing sender address: " + sender
+ ": did not start and end with < >");
return;
}
MailAddress senderAddress = null;
//Remove < and >
sender = sender.substring(1, sender.length() - 1);
if (sender.length() == 0) {
//This is the <> case. Let senderAddress == null
} else {
try {
senderAddress = new MailAddress(sender);
} catch (Exception pe) {
out.println("501 Syntax error in parameters or arguments");
getLogger().error("Error parsing sender address: " + sender
+ ": " + pe.getMessage());
return;
}
}
state.put(SENDER, senderAddress);
out.println("250 Sender <" + sender + "> OK");
}
}
private void doRCPT(String command,String argument,String argument1) {
if (!state.containsKey(SENDER)) {
out.println("503 Need MAIL before RCPT");
} else if (argument == null || !argument.equalsIgnoreCase("TO")
|| argument1 == null) {
out.println("501 Usage: RCPT TO:<recipient>");
} else {
Collection rcptColl = (Collection) state.get(RCPT_VECTOR);
if (rcptColl == null) {
rcptColl = new Vector();
}
String recipient = argument1.trim();
if (!recipient.startsWith("<") || !recipient.endsWith(">")) {
out.println("Syntax error in parameters or arguments");
getLogger().error("Error parsing recipient address: "
+ recipient
+ ": did not start and end with < >");
return;
}
MailAddress recipientAddress = null;
//Remove < and >
recipient = recipient.substring(1, recipient.length() - 1);
try {
recipientAddress = new MailAddress(recipient);
} catch (Exception pe) {
out.println("501 Syntax error in parameters or arguments");
getLogger().error("Error parsing recipient address: "
+ recipient + ": " + pe.getMessage());
return;
}
// If this is a delivery failure notification (MAIL FROM: <>)
// we don't enforce authentication
if (authRequired && state.get(SENDER) != null) {
// Make sure the mail is being sent locally if not
// authenticated else reject.
if (!state.containsKey(AUTH)) {
String toDomain = recipientAddress.getHost();
if (!mailServer.isLocalServer(toDomain)) {
out.println("530 Authentication Required");
getLogger().error(
"Authentication is required for mail request");
return;
}
} else {
// Identity verification checking
if (verifyIdentity) {
String authUser = (String)state.get(AUTH);
MailAddress senderAddress
= (MailAddress)state.get(SENDER);
boolean domainExists = false;
if (!authUser.equalsIgnoreCase(
senderAddress.getUser())) {
out.println("503 Incorrect Authentication for Specified Email Address");
getLogger().error("User " + authUser
+ " authenticated, however tried sending email as "
+ senderAddress);
return;
}
if (!mailServer.isLocalServer(
senderAddress.getHost())) {
out.println("503 Incorrect Authentication for Specified Email Address");
getLogger().error("User " + authUser
+ " authenticated, however tried sending email as "
+ senderAddress);
return;
}
}
}
}
rcptColl.add(recipientAddress);
state.put(RCPT_VECTOR, rcptColl);
out.println("250 Recipient <" + recipient + "> OK");
}
}
private void doNOOP(String command,String argument,String argument1) {
out.println("250 OK");
}
private void doRSET(String command,String argument,String argument1) {
resetState();
out.println("250 OK");
}
private void doDATA(String command,String argument,String argument1) {
if (!state.containsKey(SENDER)) {
out.println("503 No sender specified");
} else if (!state.containsKey(RCPT_VECTOR)) {
out.println("503 No recipients specified");
} else {
out.println("354 Ok Send data ending with <CRLF>.<CRLF>");
try {
// parse headers
InputStream msgIn
= new CharTerminatedInputStream(in, SMTPTerminator);
// if the message size limit has been set, we'll
// wrap msgIn with a SizeLimitedInputStream
if (maxmessagesize > 0) {
if (DEEP_DEBUG) {
getLogger().debug("Using SizeLimitedInputStream "
+ " with max message size: "
+ maxmessagesize);
}
msgIn = new SizeLimitedInputStream(msgIn, maxmessagesize);
}
//Removes the dot stuffing
msgIn = new SMTPInputStream(msgIn);
//Parse out the message headers
MailHeaders headers = new MailHeaders(msgIn);
// if headers do not contains minimum REQUIRED headers fields,
// add them
if (!headers.isSet("Date")) {
headers.setHeader("Date",
RFC822DateFormat.toString(new Date()));
}
if (!headers.isSet("From") && state.get(SENDER) != null) {
headers.setHeader("From", state.get(SENDER).toString());
}
//Determine the Return-Path
String returnPath = headers.getHeader("Return-Path", "\r\n");
headers.removeHeader("Return-Path");
if (returnPath == null) {
if (state.get(SENDER) == null) {
returnPath = "<>";
} else {
returnPath = "<" + state.get(SENDER) + ">";
}
}
//We will rebuild the header object to put Return-Path and our
// Received message at the top
Enumeration headerLines = headers.getAllHeaderLines();
headers = new MailHeaders();
//Put the Return-Path first
headers.addHeaderLine("Return-Path: " + returnPath);
//Put our Received header next
headers.addHeaderLine("Received: from " + state.get(REMOTE_NAME)
+ " ([" + state.get(REMOTE_IP) + "])");
String temp = " by " + this.helloName + " ("
+ softwaretype + ") with SMTP ID " + state.get(SMTP_ID);
if (((Collection)state.get(RCPT_VECTOR)).size() == 1) {
//Only indicate a recipient if they're the only recipient
//(prevents email address harvesting and large headers in
// bulk email)
headers.addHeaderLine(temp);
headers.addHeaderLine(" for <"
+ ((Vector)state.get(RCPT_VECTOR)).get(0).toString()
+ ">;");
} else {
//Put the ; on the end of the 'by' line
headers.addHeaderLine(temp + ";");
}
headers.addHeaderLine(" "
+ RFC822DateFormat.toString(new Date()));
//Add all the original message headers back in next
while (headerLines.hasMoreElements()) {
headers.addHeaderLine((String)headerLines.nextElement());
}
ByteArrayInputStream headersIn
= new ByteArrayInputStream(headers.toByteArray());
MailImpl mail = new MailImpl(mailServer.getId(),
(MailAddress)state.get(SENDER),
(Vector)state.get(RCPT_VECTOR),
new SequenceInputStream(headersIn, msgIn));
// if the message size limit has been set, we'll
// call mail.getSize() to force the message to be
// loaded. Need to do this to limit the size
if (maxmessagesize > 0) {
mail.getSize();
}
mail.setRemoteHost((String)state.get(REMOTE_NAME));
mail.setRemoteAddr((String)state.get(REMOTE_IP));
mailServer.sendMail(mail);
} catch (MessagingException me) {
//Grab any exception attached to this one.
Exception e = me.getNextException();
//If there was an attached exception, and it's a
//MessageSizeException
if (e != null && e instanceof MessageSizeException) {
getLogger().error("552 Error processing message: "
+ e.getMessage());
// Add an item to the state to suppress
// logging of extra lines of data
// that are sent after the size limit has
// been hit.
state.put(MESG_FAILED, Boolean.TRUE);
//then let the client know that the size
//limit has been hit.
out.println("552 Error processing message: "
+ e.getMessage());
} else {
out.println("451 Error processing message: "
+ me.getMessage());
getLogger().error("Error processing message: "
+ me.getMessage());
me.printStackTrace();
}
return;
}
getLogger().info("Mail sent to Mail Server");
resetState();
out.println("250 Message received");
}
}
private void doQUIT(String command,String argument,String argument1) {
out.println("221 " + state.get(SERVER_NAME)
+ " Service closing transmission channel");
}
private void doUnknownCmd(String command,String argument,
String argument1) {
if (state.get(MESG_FAILED) == null) {
out.println("500 " + state.get(SERVER_NAME)
+ " Syntax error, command unrecognized: " + command);
}
}
}
1.1 jakarta-james/proposal/sasl/src/org/apache/james/smtpserver/SaslProfile.java
Index: SaslProfile.java
===================================================================
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.james.smtpserver;
import cryptix.jce.provider.CryptixCrypto;
import cryptix.sasl.Base64;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import javax.security.sasl.*;
import org.apache.avalon.framework.logger.AbstractLoggable;
import org.apache.log4j.BasicConfigurator;
class SaslProfile extends AbstractLoggable {
private SaslServer server = null;
private DataInputStream in = null;
private PrintWriter out = null;
static {
// Set up a simple configuration that logs on the console.
BasicConfigurator.configure();
// Make use of Cryptix JCE and SASL libraries
java.security.Security.addProvider(new CryptixCrypto());
Sasl.setSaslClientFactory(new cryptix.sasl.ClientFactory());
}
SaslProfile(SaslServer _server, DataInputStream _in, PrintWriter _out) {
this.server = _server;
this.in = _in;
this.out = _out;
}
boolean doAUTH(String initialResponse) {
// It receives a request from the client requesting authentication for
// a particular SASL mechanism, accompanied by an optional initial
// response.
try
{
// It processes the initial response and generates a challenge
// specific for the SASL mechanism to be sent back to the client if
// the response is processed successfully. If the response is not
// processed successfully, it sends an error to the client and
// terminates the authentication session.
byte[] challenge = null;
byte[] response = null;
challenge =
server.evaluateResponse(Base64.decode(initialResponse));
System.err.println("1");
if (challenge != null) {
System.err.println("334 "+Base64.encode(challenge));
out.println("334 "+Base64.encode(challenge));
}
else {
if (server.isComplete()) {
return true;
} else {
System.err.println("334 ");
out.println("334 ");
}
}
// Responses/challenges are exchanged with the client. If the
// server cannot successful process a response, the server sends an
// error to the client and terminates the authentication. If the
// server has completed the authentication and has no more
// challenges to send, it sends a success indication to the client.
System.err.println("2");
do {
try {
System.err.println("3");
String input = in.readLine().trim();
System.err.println("input: '"+input+"'");
if (server.isComplete()) return true;
challenge = server.evaluateResponse(Base64.decode(input));
if (challenge != null) {
System.err.println("334 "+Base64.encode(challenge));
out.println("334 "+Base64.encode(challenge));
}
else {
if (server.isComplete()) {
return true;
} else {
System.err.println("334 ");
out.println("334 ");
}
}
}
catch (IOException e) {
System.err.println("IOException: "+e.toString());
return false;
}
} while (!server.isComplete());
return true;
// If the authentication has completed successfully, the server
// extracts the authorization ID of the client from the SaslServer
// instance (if appropriate) to be used for subsequent access
// control checks.
// For the rest of the session, messages to and from the client are
// encoded and decoded using the input and output streams that
// encapsulate the negotiated security layer (if any).
}
catch (SaslException e) {
System.err.println("SaslException: "+e.toString());
return false;
}
}
}
--
To unsubscribe, e-mail: <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>