package nl.west.aaa;
import java.util.*;
import java.io.*;
/**
* A AAA message.
* A Messages consists of a type and attributes.
* The attributes are stored in
* attributename-attributevalue pairs.
* A message should at least have the following
* attributes:
* <dl>
* <li><code>sid</code> - <i>session-id</i>
* identifying the session this message belongs to.
* Replies are found by mathcing session-ids.</li>
* <li><code>uid</code> - <i>user-id</i>
* identifying the user of the session (or the
* user wishing authentication.</li>
* </dl>
*/
public class Message
{
// AUTHENTICATION MESSAGETYPES
/**
* Client requests authentication of user.
*/
public static final int AUTHENTICATION_REQUEST = 0x0100;
/**
* Server accepts authentication of user based
* on sent data.
*/
public static final int AUTHENTICATION_ACCEPT = 0x0101;
/**
* Server rejects authentication of user based
* on sent data.
*/
public static final int AUTHENTICATION_REJECT = 0x0102;
/**
* Server needs more data to complete authentication
* of user.
*/
public static final int AUTHENTICATION_CHALLENGE = 0x0103;
/**
* Server requests redo of athentication.
* Client should respond with a request.
* Session may be suspended depending on
* attributes and settings.
*/
public static final int AUTHENTICATION_REDO = 0x0104;
// AUTHORISATION MESSAGETYPES
public static final int AUTHORISATION_REQUEST = 0x0200;
public static final int AUTHORISATION_ACCEPT = 0x0201;
public static final int AUTHORISATION_REJECT = 0x0202;
public static final int AUTHORISATION_CHALLENGE = 0x0203;
public static final int AUTHORISATION_REDO = 0x0204;
// ACCOUNTING MESSAGETYPES
/**
* Client has accounting data for server.
*/
public static final int ACCOUNTING_REQUEST = 0x0300;
/**
* Server confirms receiving accounting data.
* This may be used to transmit a signature over
* the sent data.
*/
public static final int ACCOUNTING_REPLY = 0x0301;
/**
* The server requests that the client send
* accounting messages regarding specified
* (may be all) sessions currently active.
*/
public static final int ACCOUNTING_POLL = 0x0302;
/**
* The server requests that the client send
* accounting messages regarding specified
* (may be all) sessions currently active.
*/
public static final int ACCOUNTING_INDICATION = 0x0303;
// OTHER MESSAGETYPES
/**
* The server requests that all buffered messages be
* sent.
*/
public static final int MESSAGES_REQUEST = 0x0400;
/**
* Thge client indicates that there are buffered
* messages waiting to be delivered.
*/
public static final int MESSAGES_READY = 0x0401;
/**
* A reject is sent when a received message
* cannot be processed for any reason.
*/
public static final int MESSAGE_REJECT = 0x0500;
/**
* The encoded encoded form of the message.
* This field may be null at any time.
*/
public transient byte[] data;
/**
* The type of the Message. See static fields
* for possible values.
*/
private int type;
/**
* The attributes of the message.
*/
private Hashtable attrs;
/**
* Idicates the used RecordFormat to encode this message.
* This field may be null and is not part of the content of the
* Message.
*/
public RecordFormat recordFormat;
/**
* Idicates the used TransportProtocol to send this message.
* This field may be null and is not part of the content of the
* Message.
*/
public TransportProtocol transportProtocol;
/**
* The sender of the message.
* This field may be null and is not part of the content of the
* Message.
*/
public Identifier sender;
/**
* The receiver of this message.
* This field may be null and is not part of the content of the
* Message.
*/
public Identifier receiver;
/**
* Make a new message of the given type
* with the given attributes.
*/
public Message(int type,Hashtable attrs)
{
// serviceID should be in attrs
this.type=type;
this.attrs=attrs;
}
/**
* Make a new message based on the given message.
*/
protected Message(Message msg)
{
this.type=msg.type;
this.attrs=(Hashtable)msg.attrs.clone();
this.recordFormat=msg.recordFormat;
this.transportProtocol=msg.transportProtocol;
this.sender=msg.sender;
this.receiver=msg.receiver;
//this.foundReply=null;
}
/**
* Return a string representation of the messageType.
*/
private static String typeString(int type)
{
switch(type)
{
case Message.AUTHENTICATION_REQUEST:
return "AUTHENTICATION_REQUEST";
case Message.AUTHENTICATION_ACCEPT:
return "AUTHENTICATION_ACCEPT";
case Message.AUTHENTICATION_REJECT:
return "AUTHENTICATION_REJECT";
case Message.AUTHENTICATION_CHALLENGE:
return "AUTHENTICATION_CHALLENGE";
case Message.AUTHENTICATION_REDO:
return "AUTHENTICATION_REDO";
case Message.AUTHORISATION_REQUEST:
return "AUTHORISATION_REQUEST";
case Message.AUTHORISATION_ACCEPT:
return "AUTHORISATION_ACCEPT";
case Message.AUTHORISATION_REJECT:
return "AUTHORISATION_REJECT";
case Message.AUTHORISATION_CHALLENGE:
return "AUTHORISATION_CHALLENGE";
case Message.AUTHORISATION_REDO:
return "AUTHORISATION_REDO";
case Message.ACCOUNTING_REQUEST:
return "ACCOUNTING_REQUEST";
case Message.ACCOUNTING_REPLY:
return "ACCOUNTING_REPLY";
case Message.ACCOUNTING_POLL:
return "ACCOUNTING_POLL";
case Message.MESSAGES_REQUEST:
return "MESSAGES_REQUEST";
case Message.MESSAGES_READY:
return "MESSAGES_READY";
case Message.MESSAGE_REJECT:
return "MESSAGE_REJECT";
default:
// return a numeric representation
return ""+type;
}
}
/**
* Produces a string representation of
* the message for debug purposes.
*/
public String toString()
{
return "Message{type="+typeString(type)+
",sender="+sender+
",receiver="+receiver+
",attrs="+attrs+"}";
}
/**
* Checks if this message is a valid reply
* to the given message.
* Subclasses could check signatures.
* This class compares session ids (sid attributes)
* and messagetypes.
*/
// TODO: realy change to something like a ReplyMatcher interface
// because reply-matching is very service dependant
// TODO: change to something with a factory thingy
// where this is delegated to the factory
public boolean isReplyTo(Message msg)
{
// first check the messagetype
switch(msg.type)
{
case Message.AUTHENTICATION_REQUEST:
switch(this.type)
{
case Message.AUTHENTICATION_ACCEPT:
case Message.AUTHENTICATION_REJECT:
case Message.AUTHENTICATION_CHALLENGE:
break;
default:
return false;
}
break;
case Message.AUTHENTICATION_CHALLENGE:
switch(this.type)
{
case Message.AUTHENTICATION_REQUEST:
break;
default:
return false;
}
break;
case Message.AUTHORISATION_REQUEST:
switch(this.type)
{
case Message.AUTHORISATION_ACCEPT:
case Message.AUTHORISATION_REJECT:
case Message.AUTHORISATION_CHALLENGE:
break;
default:
return false;
}
break;
case Message.AUTHORISATION_CHALLENGE:
switch(this.type)
{
case AUTHORISATION_REQUEST:
break;
default:
return false;
}
break;
case Message.ACCOUNTING_REQUEST:
switch(this.type)
{
case ACCOUNTING_REPLY:
break;
default:
return false;
}
break;
}
// every message should have a session id
String osid=(String)msg.attrs.get("sid");
String tsid=(String)this.attrs.get("sid");
if((osid==null)||(tsid==null))
return true;
if(!osid.equals(tsid))
return false;
return true;
// TODO: improve reply-matching
}
/**
* Make a reply to this message
* with given messageType and attributes.
*/
public Message reply(int type,Hashtable attrs)
{
Message msg=new Message(type,attrs);
msg.recordFormat=this.recordFormat;
msg.transportProtocol=this.transportProtocol;
msg.sender=this.receiver;
msg.receiver=this.sender;
// copy session id (any message should have one)
if (this.attrs.get("sid")!=null)
msg.attrs.put("sid",this.attrs.get("sid"));
//msg.attrs.put("uid",this.attrs.get("uid"));
//msg.replyTo=this;
return msg;
}
/**
* Make a new message to forward to
* the specified destination.
* The attributes and messageType are not
* modified.
*/
public Message forward(Identifier to)
{
Message msg=new Message(this);
msg.sender=msg.receiver;
msg.receiver=to;
return msg;
}
public int getMessageType()
{
return type;
}
public Object getAttribute(String attname)
{
return attrs.get(attname);
}
public Hashtable getAttributes()
{
return attrs;
}
}
|