Ajanta | A System for Mobile Agent Programming - CiteSeerX

1 downloads 4991 Views 241KB Size Report
commerce on the Web, thus acting as personal assistants for their owners. ..... host. In this situation, the hosting server uses the agent's code base URN, which ...
Ajanta | A System for Mobile Agent Programming Anand R. Tripathi, Neeran M. Karnik, Manish K. Vora and Tanvir Ahmed Department of Computer Science, University of Minnesota Minneapolis MN 55455

Abstract

This paper gives an overview of Ajanta, a Java-based system for mobile agent programming. We discuss the Ajanta architecture, and elaborate on the mechanisms used to provide object mobility, and secure execution of mobile agents in con ned protection domains. The agent programming environment is de ned, in terms of a set of primitive operations. A proxy-based ne-grained access control mechanism for application-de ned resources is described. We show how it can be adapted to provide secure inter-agent communication. We also describe a scheme for agent migration control that we have developed, based on the composition of some fundamental migration patterns. These patterns encapsulate the abstract notion of agent mobility, and incorporate some failure recovery mechanisms.

1 Introduction Ajanta is a system for programming agent-based applications over the Internet. In a broad sense, a mobile agent is a program which represents a user in a network and is capable of migrating autonomously from node to node, performing computations on behalf of the user. The main advantages of the mobile agent paradigm lie in its ability to move client code and computation to remote server resources, and in permitting increased asynchrony in client-server interactions[9, 2]. Mobile agents introduce a higher level of abstraction (in comparison to RPC and message-passing), for which many applications are naturally suited. The programmer can de ne agents as active application components that traverse the network performing computations relevant to their current location. The agent paradigm o ers the promise of utility in many potential applications. For example, agents can be used for information searching, ltering and retrieval, and for electronic commerce on the Web, thus acting as personal assistants for their owners. As tools for system administration, they can be used in low-level network maintenance, testing, fault diagnosis, and for installing or upgrading software on remote machines. Agents are also useful for extending or modifying the capabilities of existing services by dynamically adding to their functionality. Security and robustness concerns about mobile agents are the biggest hurdle preventing the widespread use of agent-based applications. The use of mobile agents requires a participating host in the system to provide a facility for executing them. It is generally required that only authorized agents be able to execute on a host and perform any operations. Unless some countermeasures are taken, agents can potentially leak, destroy or alter sensitive data and disrupt the normal functioning of the host. Malicious agents can also cause inordinate consumption of host resources, thereby denying their use to other legitimate users. Security mechanisms are thus necessary to safeguard hosts' resources. Similarly, agents themselves need to be protected from their hosts, as an agent may carry sensitive information about the user it represents. Robustness concerns in mobile agent execution also require that an agent's owner have full control over its roaming agent. An agent's owner should be able to monitor its agents periodically or recall any of its mobile agents at any time.

The main focus of the Ajanta design is on mechanisms for secure and robust executions of mobile agents in open systems. In Ajanta, the mobile agent paradigm is based on the generic concept of a network mobile object[13]. Agents in this system are active mobile objects, which encapsulate code and execution context along with data. Ajanta is implemented using the Java[6] language and its security mechanisms are designed based on Java's security model[3]. It also makes use of several other facilities of Java, such as object serialization, re ection, and remote method invocation. This paper provides an overview of the Ajanta architecture, describing its facilities for agent execution, migration, and inter-agent communication, and focuses on two important contributions: 1. A mechanism that allows a host to grant a mobile agent access to its local resources with any desired level of access control granularity. A resource owner can alter the access control policy dynamically, at runtime. Based on Java's security model, we develop a set of rules that are adopted by a host, ensuring the integrity of this protection mechanism. 2. A high-level programming abstraction based on the concept of composable patterns of migration for building agent-based applications. A migration pattern abstracts an agent's migration path and separates such speci cations from the agent's computation code. The mechanisms described here have been implemented and integrated in a prototype of the Ajanta system, which we are currently using for experimentation. We are also working on the integration of agent control and monitoring mechanisms in this system. A version of this system for public distribution is expected to be made available in the summer of 1998. The next section describes the basic components of Ajanta's system architecture along with some of the foundational protocols. Section 3 presents our approach for establishing protected bindings between a visiting agent and its host's resources. Section 4 describes the mechanism that we have devised for supporting communication between a mobile agent and its creator or other agents. The focus of Section 5 is on the programming model based on composition of migration patterns, and an overview of its implementation. Section 6 compares our approach with other agent-based programming projects. In Section 7 we present our conclusions and the directions of our future work on this project.

2 An Overview of the System Architecture

2.1 Basic Elements

A host in the Internet can provide some services to mobile agents by running Ajanta's agent server to receive visiting agents. An agent server creates a con ned execution environment for visiting agents and allows the local resource owner to grant access to its resources to agents in a selective manner. The generic agent server provides primitive operations to agent programmers, such as those which allow agents to migrate to other servers, communicate with each other, query their environment, etc. A set of agent servers cooperatively implements the mobile agent programming environment. To obtain services from or access resources of a set of such servers, a client creates an agent with appropriate directives for migration to various servers and the actions to be performed at each server. Also, mechanisms are provided for creating and assigning to an agent, in a tamper-proof 2

manner, its credentials and the privileges granted to it by its owner. A principal in Ajanta is an entity which has a unique identity in the system. Actions in the system are always performed on behalf of some authorized principal. Agents, service providers, hosts, agent servers and human users are some of the principals in the system. Each agent has an owner { this is the human user whom the agent represents. The agent itself may be created by another entity { such as an application program, or another agent. Thus the creator of an agent is usually distinct from its owner. These principals are encoded in each agent's credentials. The design of the Ajanta system has been directed by the following requirements: 1. Protection of host resources is an important concern. Therefore, the system should provide suitable mechanisms to agent servers to specify and enforce any desired policies of access control for its resources. Such mechanisms should also facilitate metering of resource usage and dynamic and selective revocation of privileges granted to an agent. 2. To facilitate communication between mobile objects, the system should support a locationindependent naming scheme. It should be possible to name any entity in the system (such as an agent, agent server, or a global resource) and access it without any knowledge of its location. 3. It should be possible for an agent's creator to monitor the status of its agent and recall it at any time. Exceptions encountered by the agent should be gracefully handled, or propagated to its creator. 4. For constructing mobile agents, high-level programming abstractions should be provided to application programmers to enhance ease of design and programming. Such programming abstractions should also permit integration of user-de ned mechanisms for recovery from common failure conditions. We use Java's object serialization facility to implement agent mobility. Thus agents are simply serializable Java objects. Note however that object serialization only captures the data values in an object's state; it cannot capture the execution state of the thread (or threads) currently executing in the object. Thus, when the object is deserialized at the remote host, a new thread is assigned to execute a method speci ed in the migration request. An alternative approach is to capture the thread-level execution state of the agent and transport it along with the code and data. We rejected this approach because its necessitates modifying the Java virtual machine, and has the disadvantage of making the system incompatible with standard Java installations.

2.2 Uniform Naming Scheme

To comply with our requirement of location-independent names, we adopted the Uniform Resource Name (URN)[22] scheme. A URN is a persistent, location-independent resource identi er which can be used for accessing the characteristics of the resource, or the resource itself. The name service framework has to address three security requirements: (1) access control on the name server registry entries, (2) server authentication, and (3) server replication to protect against \denial of service" attacks. To meet these requirements, a name server maintains access control lists for its entries, and public key certi cates for various principals. 3

An example of a URN in Ajanta's namespace is \urn:ans:cs.umn.edu/ahmed/aName" where \ans" is the Ajanta Namespace Identi er (NID)[16] and \cs.umn.edu/ahmed/aName" is the Namespace Speci c String (NSS). We used the existing simple resolution framework of the Domain Name System (DNS) for URN resolution (the translation of URN to URL or another URN or any other characteristics). In the above URN example, \cs.umn.edu" is the DNS domain name where the object was created. It is known as creation domain which could be used as a hint to locate an object; \ahmed" could be a naming authority or a subdomain, and \aName" is a unique string in this subdomain. This hierarchical structure provides ease of maintenance and delegation of namespaces. The current implementation of the name registry provides three kinds of functional interfaces: and lookup. The bind primitive sets up the initial association between a URN and a speci ed registry entry. The rebind primitive binds an already-bound URN to a new registry entry when, for example, an agent moves to a di erent location. The lookup primitive returns name registry entry information for a URN. It is also possible to perform selective lookups; for example: getURLs returns a list of locations (URLs) mapped to a URN, getURNType returns the type of URN (agent, agent-server, code-base server or other), getPublicKey returns the public key for the speci ed URN.

bind, rebind

The URN resolution procedure rst queries the local nameserver. If it is unable to resolve locally, it queries the nameserver in the creation domain. The creation domain nameserver maintains all the URNs created in its domain and contains the authoritative version of their name registry entry. In our current implementation, whenever an object migrates, its creation domain is updated. If an object migrates to a domain other than its creation domain, then both the current domain as well as the creation domain nameservers are updated. We are presently investigating other design options for the location update and resolution protocol.

2.3 Primitives for Agent Programming

Agents in Ajanta are written as subclasses of the base class Agent. This class provides a reference (called host) to the agent environment, i.e., the agent server currently hosting it (see Fig. 1). When an agent arrives at a server, this host reference is appropriately initialized before the agent starts executing. The agent environment provides di erent types of services in the form of primitives invocable by the agent. These are described below.

2.3.1 Agent Creation and Dispatch An agent can be created by simply instantiating a subclass of the base Agent class. Typically, the agent's creator provides it with a set of credentials, which are described in Sec. 2.4. The agent is also usually customized by providing it an itinerary and possibly other application-speci c data. A newly created agent is a passive object. It is activated by dispatching it to some agent server for execution. This is accomplished using the launch primitive. The agent's creator launches it to an agent server and optionally speci es the method to be invoked. A method speci cation consists of the method name, the types of its formal parameters, and the arguments to be passed to it. If the method speci cation is omitted, the server executes the (parameterless) run method by default. The base Agent class provides an implementation of the run method that does nothing, which can be overridden by the derived class as appropriate. 4

AGENT Current

Itinerary

Resource

Proxy1

Proxy2

Code

State

(Methods)

(Internal Data)

M1

M2

M3

AccessProtocol

Credentials

Host

Agent Environment Resource

Domain

Registry

Database

Agent Transfer

ATP

AGENT SERVER

Figure 1: The Ajanta Server Structure

2.3.2 Agent Migration An agent can request migration using the go primitive. It speci es the URN of the desired destination agent server, along with the method to be executed there. As before, if the method speci cation is omitted, the run method is invoked. The protocol followed by the agent server for performing the actual migration is described in Sec. 2.5. If the agent transfer completes successfully, the go method never returns and the thread executing it is terminated. If however an error occurs during the transfer, it throws an exception, allowing the agent to handle the error. The agent's migration path is often encoded in the form of an itinerary, as shown in Fig. 1. Operations on the itinerary can invoke the go primitive, but the server itself remains unaware of the itinerary construct. In some situations, the agent may prefer to co-locate itself with another agent or resource that it needs to access. It can use the go primitive, specifying the URN of the co-location target. The go method invokes the name service to nd the current host server of the speci ed agent or resource, and sends the caller agent to that server.

2.3.3 Resource Access Ajanta provides a generic Resource interface, which must be extended to de ne application-speci c resource interfaces. An agent can access resource instances installed on its current server using the getResource primitive. The agent speci es the URN of the desired resource. The resource instance is then made available to the agent (using a proxy-based access mechanism described in Sec. 3.2), assuming that the resource's security policy allows it. 5

2.3.4 Agent Communication An agent may itself act as a remotely callable server, allowing other agents and programs to invoke some of its methods. It can request the server to install an RMI proxy for it, using the createRMIProxy primitive. This is elaborated on further in Sec. 4.

2.4 Agent Credentials

When an agent is created, a set of credentials is assigned to it. They securely identify the agent along with some associated information, such as the identities of its owner principal, its parent (creator) object and the author of the agent's code. Each such identity includes the principal's name and public key, along with a set of certi cates providing the binding between the two. Other components of the credentials include the agent's home site URN, its code base URN and the privileges assigned to it. The home site may be used, for example, to report status information, or to return a malfunctioning agent back to its owner. During its execution, an agent requires code from several di erent classes apart from its own class. Some of these classes may be unavailable on its current host. In this situation, the hosting server uses the agent's code base URN, which identi es a server process responsible for providing the required bytecode. The class loading mechanism is detailed further in Sec. 3.1. When an agent executes on a server, the server imposes certain restrictions on its privileges, based on the identity of the agent owner. In some situations, the owner may wish to restrict these privileges even further, to prevent the agent from performing any dangerous actions for which the owner may be held liable. Such restrictions are also encoded into the agent's credentials.

2.5 The Agent Transfer Protocol

Ajanta's agent transfer protocol (ATP) is cooperatively implemented by the agent servers in the system. It is invoked when an agent requests migration to another agent server, or when an application creates and launches an agent to its initial server. The sender must capture the state of the agent, convert it to a machine-independent format, and transmit it to the recipient server. We use Java's object serialization facility to implement this state capture. The recipient server must then deserialize this data and recreate the agent object within a protection domain of its own. When an agent server is created, it starts up an ATP Listener thread. This thread listens for connections on a particular port, which is published as part of the agent server's entry in the name service. Thus, given an agent server's URN, its DNS hostname and ATP port can be determined by consulting the name service. The ATP listener creates an ATP Handler thread to handle each incoming connection, leaving itself free to listen for further requests. The ATP handler thread thus implements the actual data transfer that comprises the agent transfer protocol. An agent's migration request contains a destination and a method speci cation. The agent's credentials and this method speci cation are bundled together with some parameters controlling the transfer itself { such as ags indicating whether the transfer should be encrypted and signed, some indication of the algorithms used for that purpose, and any parameters speci c to those algorithms. After executing a mutual authentication protocol which establishes the identities of the sending and receiving servers, the request message is transmitted to the destination server's ATP listener. The credentials identify the agent requesting a transfer, thus allowing the destination 6

server to decide whether to permit the transfer. If the transfer is permissible, the ATP handler sets up an execution environment for the incoming agent. The sending server then serializes the agent object itself, and transmits it on the same connection. It is received, deserialized and activated by the destination server. Note that the agent's code (class) is not transferred at this stage, but is loaded if necessary from its code base. This entire process is detailed in Sec. 3. Once the agent has been transferred, the receiving server sends an acknowledgement message back to the sender, which can then update the agent's location with the name service using the rebind primitive, and clean up its internal data structures to indicate that the agent is no longer hosted by it. If an error (such as a security violation) occurs before the agent can be activated, a negative acknowledgement is returned instead. The original server then informs the agent that its transfer request failed, by raising an exception.

3 Controlled Execution of Mobile Agents When a mobile agent arrives at a server, it must be executed in a controlled fashion so that it cannot cause any damage to the server's resources, and cannot be tampered with by other agents residing at that host. The two primary challenges therefore are: the creation of a protection domain in which to isolate the agent, and the provision of a secure resource access protocol.

3.1 Protection Domains for Agent Execution

In Ajanta, each incoming agent is isolated from other agents on the server, so that they are unable to interfere with each other's operation. Two Java mechanisms are used for this purpose: thread grouping and class loading. A thread group in Java is a simple collection of threads. When an agent arrives, a new thread group is created with an identi er that is unique on that server. A single thread is created in this thread group, and is assigned the task of executing the method speci ed by the agent as part of its migration request. During its execution, the agent may create other threads, but it is constrained to create them within its own thread group. Thus, any thread executing that agent's code can be identi ed by its thread group id. The agent server maintains a domain database indexed by thread group ids, in which it stores the agent's URN and credentials, as well as a reference to the agent object itself. This entry is used by the server's code whenever it needs access to the agent or its identity { for example, when an agent attempts to acquire a resource, its credentials are needed to determine the level of access permitted. We use Java's class loader mechanism to protect agents from each other. Each executing agent is assigned a separate class loader object which is responsible for locating and loading any classes that are needed by the agent's code. Whenever the agent's code encounters an object reference for which the class is not currently loaded, the Java virtual machine invokes the agent's class loader, and provides it the name of the required class. Our implementation of the class loader rst searches the server's classpath { a set of directories on the local le system which contain classes trusted by the server. If the requisite bytecode is found on the classpath, it is loaded into the virtual machine. Otherwise, the agent's code base must be contacted to nd the missing class. The code base is a URN representing a server (usually on the agent's home site) which has access to all the agent's classes. This URN is available to the agent server as part of the agent's credentials. The 7

class loader can thus contact the server and download the bytecode corresponding to the required class. This communication may be encrypted and digitally signed to ensure the authenticity of the downloaded code. The Java virtual machine associates with each class, the class loader instance that loaded it. Classes loaded by di erent loaders may have the same name, but are considered di erent types. This implies that objects of the two classes are not type-compatible, even if the classes are in fact identical. Since each agent in Ajanta is assigned a unique class loader instance, a malicious agent cannot replace any other agent's classes with its own impostor versions. In e ect, each class loader de nes its own class namespace, protecting the agent's code from tampering by other agents.

3.1.1 Agent Activation

When an agent transfer connection is initiated, the ATP handler thread rst reads the transfer request message from the sender. This contains the credentials of the agent being transferred. The handler consults the server's security policy to determine whether to allow the transfer to continue. If the agent is not permitted to execute on the server, the connection is closed, and the sending server informs the agent of failure by raising an exception. Otherwise, the ATP handler creates a new thread group, a new thread in that group, and a class loader instance for the agent. An entry for the agent is made into the domain database. The newly created thread uses a bootstrap mechanism to transfer control into the new class loader's namespace. It then deserializes the agent object from the incoming connection, and sets the agent's host reference to point to the local server's agent environment object (see Fig. 1). The base Agent class de nes an empty arrive method, which can be overridden by the agent programmer to execute an entry protocol at every hop in its itinerary. This method is now executed by the agent thread, followed by the invocation of the method speci ed in the agent's transfer request. Finally, when the agent nishes its task at this server, its exit protocol, in the form of a depart method, is executed.

3.2 Secure Resource Access for Agents

Agents on a server need access to di erent types of resources as they execute. These include systemlevel resources such as les, network connections, screen space (windows), etc. as well as arbitrary application-de ned resources. The server must grant resource access only to authorized agents, and then only to the extent permitted by their privileges. System-level resources are protected in Java using the security manager, an object which encodes the security policy. All Java library calls which access system resources rst invoke the security manager to screen the access. If the security policy dictates that the access should be denied, the security manager throws an exception. For application-level resources however, we chose not to burden the security manager further. Every new resource added to the system would necessitate extending the security manager, making it a large, uncohesive module prone to errors (and thereby, security loopholes). Therefore, we need to implement a mechanism which allows the agent server to provide a secure language-level binding between agents and resources. Each resource must be allowed to de ne its own security policy, and control its implementation. Our approach is based on proxy interposition[21] between the resource and its clients (i.e., agents). We illustrate the protocol below using a simple example in which we 8

develop a bounded-bu er resource. Next, we discuss the resource request protocol which agents use to access instances of the bu er resource.

3.2.1 De ning Resource Classes Resource

AccessProtocol

BufferImpl

KEY:

class interface

Buffer

ResourceImpl

BufferProxy

implementation inheritance interface inheritance

public interface Resource { // generic methods, common to all resources } public class ResourceImpl implements Resource { // implementations of the generic methods } public interface AccessProtocol { public Resource getProxy (Credentials cred); }

Figure 2: Resource Class Hierarchy

Figure 3: Generic Resource Interfaces

The Ajanta system de nes a Resource interface, and provides a ResourceImpl class which implements it (see Figures 2 and 3). The methods of this class provide generic functionality common to all resources, such as resource naming and ownership. Application-de ned resource classes must implement the Resource interface; this is typically done by simply inheriting from the ResourceImpl class. In order to make itself securely available to agents, the resource class must also implement the system-de ned AccessProtocol interface, i.e., a getProxy method, which is elaborated on in Sec. 3.2.2. In our example, the application provides a Buffer resource interface (implemented by a BufferImpl class) as shown in Fig. 4. public interface Buffer extends Resource { // An application-defined Buffer resource interface, which defines the operations on // a bounded buffer shared by several producer and consumer agents. public synchronized BufItem get(); public synchronized void put (BufItem); // etc. } public class BufferImpl extends ResourceImpl implements Buffer, AccessProtocol { // implementations of the Buffer and AccessProtocol interface methods }

Figure 4: A Bounded Bu er Resource

3.2.2 Binding using Proxies

The resource binding protocol is de ned in terms of generic Resource objects so as to keep it independent of application-de ned resource types. Agents are never provided with direct references 9

to resource objects. Instead, when an agent requests a resource, an instance of its proxy class is returned. For each application-de ned resource class, a corresponding proxy class must be available. The proxy class can be automatically generated by a simple lexical processing tool. public class BufferProxy implements Buffer { private transient Buffer ref; // private reference to underlying resource private transient Method[] enabledMethods; BufferProxy(Buffer b, Method[] e) { ref = b; enabledMethods = e; } public synchronized BufItem put (BufItem x) { Class[] ptypes = new Class[1]; ptypes[0] = Class.forName ("BufItem"); Method me = this.getClass().getMethod ("put", ptypes); if (checkAccess(me)) ref.put(x); else throw new SecurityException("Unauthorized method access"); } private boolean checkAccess(Method m) { // Checks if the method m is enabled in this proxy instance. } public void enable (Method m){ // Modify proxy to allow the method m to be executed. } public void disable (Method m){ // Modify proxy to disallow execution of method m. } }

Figure 5: Proxy class for the bounded bu er Each resource class must implement the AccessProtocol interface, i.e., a getProxy method, which creates a new instance of its proxy class customized for the caller agent. The proxy object contains a private reference to the resource it represents. It also contains a private array of method objects, called enabledMethods, which represents the set of proxy methods that the agent is permitted to invoke. The getProxy method initializes this set during proxy construction, based on the agent's credentials in conjunction with its security policy. Each proxy class implements all the methods of its resource's interface (i.e. Buffer in this case), and also provides three additional methods { enable, disable, and checkAccess. The purpose of the rst two is to dynamically add to or remove from the set of enabled methods. The checkAccess method is used by each of the proxy methods to verify that the method is currently permitted. Note that the enable and disable methods are privileged { only a thread in the server's domain is allowed to execute these methods. Thus, agents cannot tamper with the proxy objects allocated to them. Figure 5 shows the relevant parts of the proxy class corresponding to the Buffer resource. Note the class constructor which initializes the initial set of enabled methods, and the implementation of the put method, which uses re ection to rst obtain a reference to its method object, and then calls checkAccess to determine if this reference is present in the array enabledMethods. 10

3.2.3 Resource Request Protocol Each agent server maintains a Resource Registry (see Fig. 1), which facilitates the binding between its resources and agents. For each resource, the registry contains the URN and a reference to the resource object itself, besides other information (such as resource ownership). An agent must invoke the getResource method on its host (environment) object to obtain access to any resource. For our bu er example, the agent would execute: Buffer buf = (Buffer) host.getResource ("bounded_buffer");

The agent supplies the name of the resource it needs, as a parameter to the call. The server nds the corresponding object in the resource registry and makes an \upcall" to its getProxy method, providing the calling agent's credentials as a parameter. The resource object then creates an appropriately restricted proxy, and passes it back to the agent. This interposition of the proxy between the agent and the requested resource remains transparent to the agent. From the agent's perspective, a Buffer object has been made available. It can thus invoke any of the Buffer interface methods on that object. The proxy merely ensures that the method is enabled before passing the invocation through to the embedded resource reference.

3.2.4 Securing against Potential Threats The scheme presented above is now examined against the potential threats of various kinds of attacks. We introduce some additional rules, based on Java's security model, to guard against these threats and ensure the integrity of the proposed mechanism. A proxy contains an embedded reference to the resource object. The agent may attempt to directly (or via re ection) invoke the methods of this object, bypassing the proxy's access control checks. To prevent this, we rely on Java's encapsulation mechanism, by declaring the embedded resource reference as private. If the proxy object could be typecast to another type which bypassed the access control checks for each method, the agent could gain unauthorized access to the resource. In our scheme however, we enforce the rule that a proxy class has no ancestors apart from the base Object class. Thus, Java will not allow the agent to typecast the proxy instance to any other class. When the agent arrives across the network, it typically also provides its own code base. In doing so, it may attempt to install its own version of the proxy class, which bypasses access control checks or makes the embedded resource publicly available. However, Ajanta's class loader makes sure that the proxy class is only loaded from the classpath. A malicious agent could serialize a proxy, transmit the byte stream to a cooperative agent server (possibly its own home site) and deserialize it using a fake proxy class, thus exposing the underlying resource. We prevent this by enforcing the rule that the resource reference within a proxy class must be declared as transient. Java does not include transient references in the byte stream generated by object serialization. The agent, having followed the proper protocol to obtain a proxy, may attempt to clone it. While this does not result in the cloning of the underlying resource, it can a ect accounting and 11

revocation mechanisms built into the proxy. To avoid this, we enforce the rule that the proxy class does not implement the Cloneable interface. Java does not allow the cloning of any object which does not implement this interface.

4 Inter-Agent Communication

Communication using Resource Proxies: Two agents located on the same server can utilize the proxy-based resource access mechanism to communicate among themselves. An agent class can implement the Resource and AccessProtocol interfaces just as the Buffer does in our earlier example. The agent then registers itself with the server as a resource, and can provide proxies which allow other agents to communicate with it. Co-located agents may also communicate via shared access to a resource on their server (e.g. a simple bu er object for which both agents have proxies). However, in many applications, agents residing on di erent servers may need to communicate or synchronize with each other. Thus a remotely invocable communication mechanism is necessary.

Security Concerns: If an agent is allowed to present an RMI interface to the outside world, it

opens up a security loophole. The agent itself may be granted access to certain resources by the server. But the RMI interface provides a conduit to leak the information to unauthorized principals on remote sites. We need to authenticate incoming and outgoing connections, so as to control the set of principals which have indirect access to a resource. The proxy interposition concept is used here too, to control incoming connections. Outgoing connections are monitored by the security manager.

Installing a Proxy RMI Server: An agent wishing to make itself available for remote invoca-

tion must use the createRMIProxy primitive. It speci es the interface that it intends to support, and requests the server to create and install an RMI proxy. If the server can nd a proxy class appropriate for that interface, it creates the proxy instance (containing an embedded reference to the agent object) and registers it with the local RMI registry under the agent's name. If the appropriate proxy is not available locally, the createRMIProxy fails { the agent's code base is not relied upon to provide a safe proxy class. Thus the proxy code is trusted to be safe, and will not leak information to unauthorized callers. When a remote entity wishes to communicate with such an agent, it searches the RMI registry using the agent's name. The RMI stub returned by the RMI registry however actually points to the agent's RMI proxy. All incoming RMI invocations are intercepted by the proxy, which passes the RMI call through to the agent object and relays the results back to the caller. However, if authentication of the caller is necessary, the proxy raises an RMI exception. The caller is then expected to make another RMI call, supplying its identity, including its public key certi cate. Authentication then proceeds using a challenge-response mechanism using a random nonce. Once the authorization is con rmed, the proxy relays the call to the agent as usual.

5 Patterns for Agent Programming Typical agent programs can be conceptually divided into their computational code and the code that controls their migration path. Our approach to agent programming is based on this separation of an agent's migration control from its computation. Moreover, we support building of complex 12

travel plans by composing them from some commonly occuring migration patterns. In Ajanta, we de ne a pattern as a description of an abstract migration path for an agent. These patterns should not be confused with design patterns of Gamma et al.[4] { they are not descriptions of designs; rather they provide building blocks for a travel plan. In the context of mobile agent programming, the concept of travelling patterns has been used in the past by Aridor and Lange[1]. Similar concepts have also been proposed in Java-based Moderator Templates[11]. In contrast to our approach, these are basic primitives in that they only de ne single hops, although the Java-based Moderator Templates can support some of the pattern compositions that we provide. Patterns in Ajanta are higher-level abstractions and richer in their ability to de ne migration control structures using compositions. Moreover, we integrate exception handling mechanisms in these patterns to provide resilience to some commonly occurring failures like hosts being unreachable.

5.1 Classi cation of Patterns

We now present our hierarchically-classi ed patterns (see Fig. 6).

5.1.1 Foundation Classes Pattern

ItinEntry

Sequence

PatternCollection

Selection

Split

Set

SplitJoin

Loop

Key Class

SplitJoinAll

SplitJoinAny

Abstract Class

Figure 6: Hierarchy of Patterns The root of the class hierarchy is an abstract class Pattern. Every pattern is associated with an action (speci ed by the programmer) that the agent performs at the hosts it visits. However, this can be overridden to specialize the action performed at a speci c host in that pattern. The pattern traversal is determined by the abstract method next. It captures the notion of the next hop in the migration path of the agent. Each pattern has its own semantics to determine the next hop. For example, the next hop could be the next item in a sequence, or a choice from a given set of hosts, based on some condition. 13

The basic unit of migration is de ned in terms of an ItinEntry which is a singleton Pattern. It speci es the destination server to migrate to, and the action to be performed at that host. This class is derived from the class Pattern. Its de nition of the next method is to actually migrate to the speci ed host using the go primitive.

5.1.2 Compositions of Patterns Aggregations of the basic unit (ItinEntry) can be used to form more complex patterns, such as a Sequence or a Set. These patterns in turn can be further aggregated to build any travel plan. The abstract class PatternCollection represents an aggregation of patterns. It consists of a list of patterns. The next method can then be given di erent semantics, to derive the various patterns we describe next.

Sequence: A sequence pattern is composed of an ordered list of patterns. The traversal of this pattern implies a traversal of the patterns in the list in sequential order.

Selection: This emulates the conditional control structure. The traversal of this pattern implies choosing one pattern from the list based on a user-de ned choosePattern method. This choice could be made on basis of the agent's state or the hosts to be visited in the pattern. Strategies for making a selection could be randomized, priority-based, etc. This pattern is also useful in selecting alternate paths in case of failures, like unavailability of hosts.

Set: This is an unordered list of patterns. The agent must traverse all these patterns, but the

order of traversal is immaterial, or is determined dynamically by the user-de ned choosePattern method. Hence, when the next method is called on this pattern, it chooses one amongst the list of patterns not yet traversed, and makes a hop to the next host de ned by the chosen pattern. This pattern also makes the plan more robust, since it can order paths based on host availability.

Loop: This is a simple iterator pattern. It allows the agent to repeatedly traverse a pattern until a certain user-speci ed condition is satis ed. It can be used to monitor a certain event.

Split: This pattern results in the creation of child agents for parallel traversal of contained pat-

terns. This is conceptually similar to parallelizing a Set, where instead of one agent travelling along some path de ned by the Set, each child agent is assigned one element of the Set for traversal. This pattern only controls creation and dispatch of agents. It is used when the child agents are not expected to report back to the parent.

SplitJoin: This is a specialization of the Split pattern in which the child agents must report their results to some agent (usually the parent). To achieve this, the parent appends to the child agents' itinerary, an entry to join with the speci ed agent. Each child agent, having accomplished its task, co-locates with the agent it is supposed to meet and invokes the join method on it. The join is achieved using a Synchronizer object, which in the default case is a simple counter implementing a barrier. SplitJoin is an abstract class, which can be extended by the agent programmer by de ning his own policy for joining. We have implemented two such subclasses SplitJoinAll where an agent waits for all the child agents before it proceeds, and SplitJoinAny where the agent waits for the rst child to return. 14

5.2 Pattern Traversal Itinerary

Sequence SQ1 Selection SL1 Sequence SQ2

A C B

Set ST1

Sequence SQ3

E D

G F

H

Figure 7: Building Itineraries using Pattern Composition

protected int next () throws UnknownHostException { Pattern currPattern = (Pattern) list.elementAt(current); while (optionLeft) { try currPattern.next(); catch (UnknownHostException ex) { currPattern = chooseAlternate(); if (currPattern == null) { optionLeft = false; // Propagate exception to the caller throw ex; } } } }

Figure 8:

next

method of the Selection Pattern

We now describe the role of patterns in controlling the actual migration of an agent. Each agent contains an Itinerary which encapsulates the travel plan of the agent as a Sequence pattern. The basic unit of execution for an agent is the action it performs at each host. This is its computation, which is separate from its migration control. The exit protocol (de ned by its depart method), which is executed when the agent completes its computation task, requests the Itinerary to choose the next host and migrate to it. We illustrate this process with the help of an example. Figure 7 shows an Itinerary that contains a Selection (SL1), a Set (ST1) and an ItinEntry (H). The Selection is a choice between a Sequence (SQ2) and a single host (C). The Set (ST1) consists of the hosts D, G, and a Sequence (SQ3). Therefore the actual path traversed could be < A; B; D; E; F; G; H > or < C; E; F; G; D; H > and so on. This example shows how agent programmers can use these building blocks to make a complex plan. When the agent completes its task at one host, it assigns its Itinerary the task of picking the next host and migrating to it. This is done by calling the next method on the Itinerary which initiates a recursive call, executing the next method of the Sequence SQ1. This in turn will call the next method of one of its patterns and so on until it reaches an ItinEntry, whose next method makes the actual hop. If the migration is successful, the agent is recreated at the new host, and the calling thread terminates. If it fails, an exception is thrown, which is passed up the recursion chain. If a next invocation nds that the pattern traversal is complete, it merely returns with a \completed" status. In this example, to make the rst hop, the Itinerary would call the next method of Sequence SQ1, which would call the next method of the Selection SL1. Now, the Selection must make a choice using the choosePattern method. Assume it picks the Sequence SQ2, and calls its next method, which nally picks host A and migrates to it. 15

There are two advantages of the recursive nature of this call. Firstly, each pattern can implement the next method based on its own semantics. The Itinerary and any pattern need not be concerned with its component patterns' implementations of next. Secondly, exceptions can be handled by each pattern based on its own semantics, and if needed propagated up this recursive call.

5.3 Exception Handling Model

Each pattern must de ne its own exception handling mechanism. These exception handling routines are what make this system robust. There are several di erent types of exceptions which the system must be capable of handling, e.g. UnknownHostException, HostUnreachableException, ServerOverloadedException. We illustrate with the help of an example, how patterns handle some of these exceptions. Consider the same Itinerary as described in Fig. 7. If the agent is at host A and decides to migrate, the next host it must go to is B. Assume that the name service cannot resolve host B, hence the go method throws an UnknownHostException. The ItinEntry cannot handle this, so it throws it to its caller, the Sequence SQ2. The semantics of a Sequence are such that it cannot handle this exception and must re-throw it to its caller, the Selection SL1. The Selection catches this exception and its semantics allow it to choose a di erent path. Hence, it chooses to go to host C. Note that the system makes no guarantee of atomicity of pattern traversal. Figure 8 shows the implementation of the next method of Selection. The semantics of the Set pattern also allows fault tolerance along similar lines. For example, if a particular host is unreachable or the server is overloaded, then it can choose a di erent path, and retry this path at a later time. Consider another example where exceptions would prove useful. An agent may wish to terminate the pattern it is currently traversing, since it has already found the information it was looking for. It could throw a TaskCompletedException, which would allow the Itinerary to terminate the traversal of the current pattern. For example, in Fig. 7 an agent at host D, may wish to terminate the Set pattern, and proceed ahead onto host H. The agent may also wish to terminate its entire Itinerary and return to its home site at any given instant.

6 Related Work We brie y compare our work with other projects on agent-based computing with speci c focus on two aspects: integration of security mechanisms, and paradigms for agent programming. Telescript[24] was one of the rst agent systems. It is an object-oriented type-safe language designed to support agent-based computing. It uses di erent types of permits for access control and for imposing quotas on resource use. Security mix-in classes can be used to protect objects from unauthorized modi cation, copying or migration. A comparative evaluation of three Javabased mobile agent systems is presented in [15]. The Aglets Workbench[10] developed by IBM is one of them. Currently, Aglets has only primitive security functionality. However a security architecture for this system has recently been proposed[14]. Some of the other Java-based agent systems, Voyager[18], Sumatra[20], and Mole[23], do not address security issues. 16

Tacoma[12] and Agent Tcl[7] are Tcl-based systems. The Tacoma design does not address security issues. Agent Tcl supports access control lists based on host names and uses PGP for encryption and authentication. In Ara[19], which supports multiple languages like Tcl and C++, agent servers use access control lists (called \allowances") to impose restrictions on visiting agents. For protected access to server resources by an agent, our approach is based on the concept of proxies. The proxy concept was rst developed by Shapiro[21]. It has also been recently used in other agent based systems[8]. We use proxies to act as capabilities. These capabilities may include the identity of the client, to act as an identity-based capability[5], and may also include some accounting information, as suggested in [17]. One of the contributions of our work lies in supporting proxy-based capabilities whose integrity can be assured based on Java's security model. The protection scheme described in [8] has some conceptual similarities to our approach. Both schemes use proxy objects acting as capabilities instead of direct access to resources. In [8] the restricted interfaces of such proxy classes (called lters in [8]) are statically de ned, independently by clients and servers. These restricted interfaces are integrated with the resource interface de nitions; this allows the system to automatically create and interpose appropriate lter objects in a client-server interaction. In contrast, our scheme supports dynamic de nition as well as modi cation of the access privileges assigned to an agent through a proxy. Moreover, we can argue about the integrity of our scheme based on Java's security model and present a speci c set of design rules to guard against potential attacks. The concept of migration patterns has been recently used by other researchers [11] [1] as well. The patterns described there tend to be somewhat primitive in contrast to our patterns as they are described in terms of single hops. The migration patterns in Ajanta present a higher-level abstraction in the sense that a pattern can be composed of several other patterns, simple or complex. Moreover, these patterns can also encapsulate suitable exception handling policies for common failure conditions.

7 Conclusions and Future Work We have described Ajanta, a Java-based system which permits agent programs to execute, communicate and migrate themselves securely. Building upon Java's security model, we provide a con ned execution environment for each agent, protecting it from tampering by other agents. We have also built a ne-grained access control mechanism for resources based on proxy interposition. A similar mechanism is used to enable remote invocation of an agent irrespective of its location, thus allowing the agent's creator to control it remotely. Applications can de ne their own security policies for agent transfer, resource access as well as agent-to-agent communication. We also demonstrated how abstract migration patterns can be used to simplify the task of creating complex agent itineraries by composition. These patterns incorporate failure detection and recovery for improved robustness. In future, we intend to include security mechanisms (such as authentication) also in such patterns, further simplifying the programmer's task. Another area of future work is auditability, i.e., we need to provide a mechanism to reliably determine the migration history of an agent. This is required by the agent application to determine the level of trust that can be placed in the agent's results. We also plan to implement some real-world applications which can demonstrate the utility of migration patterns, as well as exercise Ajanta's security and robustness features. 17

References [1] Yariv Aridor and Danny B. Lange. Agent Design Patterns: Elements of Agent Application Design. In Second International Conference on Autonomous Agents, May 1998. Available at http://www.acm.org/~danny/ag.pdf. [2] David M. Chess, Benjamin Grosof, Colin Harrison, David Levine, Colin Parris, and Gene Tsudik. Itinerant Agents for Mobile Computing. IEEE Personal Communications, pages 34{59, October 1995. [3] J. Steven Fritzinger and Marianne Mueller. Java Security. Technical report, Sun Microsystems, 1996. Available at http://www.javasoft.com/security/whitepaper.ps. [4] Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. Design Patterns. Elements of Reusable Object-Oriented Software. Addison-Wesley Publishing Co., 1997. [5] Li Gong. A Secure Identity-Based Capability System. In IEEE Symposium on Security and Privacy, pages 56{63, May 1989. [6] James Gosling, Bill Joy, and Guy Steele. The Java Language Speci cation. Addison-Wesley, August 1996. [7] Robert S. Gray. Agent Tcl: A exible and secure mobile-agent system. In Proceedings of the Fourth Annual Tcl/Tk Workshop (TCL 96), July 1996. [8] Daniel Hagimont and Leila Ismail. A Protection Scheme for Mobile Agents on Java. In Proceedings of the 3rd ACM/IEEE International Conference on Mobile Computing and Networking, September 1997. [9] Colin G. Harrison, David M. Chess, and Aaron Kershenbaum. Mobile Agents: Are they a good idea? Technical report, IBM Research Division, T.J.Watson Research Center, March 1995. Available at URL http://www.research.ibm.com/massdist/mobag.ps. [10] IBM. IBM Aglets Workbench Documentation web page. Available at URL http://www.trl.ibm.co.jp/aglets/documentation.html. [11] IBM. JMT (Java-based Moderator Templates) Speci cation - Alpha3. Available at URL http://www.trl.ibm.co.jp/aglets/jmt/index.html, 1998. [12] Dag Johansen, Robbert van Renesse, and Fred B. Schneider. An Introduction to the TACOMA Distributed System. Technical Report 95-23, Department of Computer Science, University of Troms, June 1995. [13] Eric Jul, Henry Levy, Norman Hutchinson, and Andrew Black. Fine-Grained Mobility in the Emerald System. ACM Transactions on Computer Systems, 6(1):109{133, February 1988. [14] Gunter Karjoth, Danny Lange, and Mitsuru Oshima. A Security Model for Aglets. IEEE Internet Computing, pages 68{77, July-August 1997. [15] Joseph Kiniry and Daniel Zimmerman. A Hands-on Look at Java Mobile Agents. IEEE Internet Computing, pages 21{30, July-August 1997. Available at http://computer.org/internet/. 18

[16] R. Moats. RFC 2141: URN Syntax. Available at URL http://www.cis.ohiostate.edu/htbin/rfc/rfc2141.html, May 1997. [17] B.C. Neuman. Proxy-based authorization and accounting for distributed systems. In Proceedings of the Thirteenth International Conference on Distributed Computing Systems, pages 283{291, May 1993. [18] ObjectSpace. ObjectSpace Voyager Core Package Technical Overview. Technical report, ObjectSpace, Inc., July 1997. Available at http://www.objectspace.com/. [19] Holger Peine and Torsten Stolpmann. The Architecture of the Ara Platform for Mobile Agents. In Proceedings of the First International Workshop on Mobile Agents (MA'97), Berlin, Germany, April 1997. Springer Verlag, LNCS #1219. [20] M. Ranganathan, Anurag Acharya, Shamik Sharma, and Joel Saltz. Network-aware Mobile Programs. In Proceedings of USENIX '97, Winter 1997. [21] Marc Shapiro. Structure and Encapsulation in Distributed Systems: The Proxy Principle. In Proceedings of the 6th International Conference on Distributed Computing Systems, pages 198{204. IEEE, 1986. [22] Karen Sollins and Larry Masinter. RFC 1737: Functional Requirements for Uniform Resource Names. Available at URL http://www.cis.ohio-state.edu/htbin/rfc/rfc1737.html, December 1994. [23] Markus Straer, Joachim Baumann, and Fritz Hohl. Mole - A Java Based Mobile Agent System. In Proceedings of the 2nd ECOOP Workshop on Mobile Object Systems, 1996. [24] Joseph Tardo and Luis Valente. Mobile Agent Security and Telescript. In Proceedings of COMPCON Spring '96, pages 58{63. IEEE, 1996.

19

Suggest Documents