diff options
Diffstat (limited to 'lib/orber/doc/src/ch_interceptors.xml')
-rw-r--r-- | lib/orber/doc/src/ch_interceptors.xml | 278 |
1 files changed, 278 insertions, 0 deletions
diff --git a/lib/orber/doc/src/ch_interceptors.xml b/lib/orber/doc/src/ch_interceptors.xml new file mode 100644 index 0000000000..27b254c4bf --- /dev/null +++ b/lib/orber/doc/src/ch_interceptors.xml @@ -0,0 +1,278 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2001</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Orber Interceptors</title> + <prepared>Nick</prepared> + <docno></docno> + <date>2001-08-16</date> + <rev></rev> + <file>ch_interceptors.xml</file> + </header> + + <section> + <title>Using Interceptors</title> + <p>For Inter-ORB communication, e.g., via <c>IIOP</c>, it is possible + to intercept requests and replies. To be able to use <c>Interceptors</c> + Orber the configuration parameter <c>interceptors</c> must be defined.</p> + + <section> + <title>Configure Orber to Use Interceptors</title> + <p>The configuration parameter <c>interceptors</c> must be defined, e.g., + as command line option:</p> + <code type="none"> +erl -orber interceptors "{native, ['myInterceptor']}" + </code> + <p>It is possible to use more than one interceptor; simply add them to the + list and they will be invoked in the same order as they appear in the list.</p> + <p>One can also active and deactivate an interceptor during + run-time, but this will only affect currently existing connections. + For more information, consult Orber's Reference Manual regarding the + operations <c>orber:activate_audit_trail/0/1</c> and + <c>orber:activate_audit_trail/0/1.</c></p> + </section> + + <section> + <title>Creating Interceptors</title> + <p>Each supplied interceptor <em>must</em> export the following functions:</p> + <list type="bulleted"> + <item><em>new_out_connection/3/5</em> - one of these operations is called when + a client application calls an object residing on remote ORB. + If an interceptor exports both versions, arity 3 and 5, which + operation that will be invoked is Orber internal.</item> + <item><em>new_in_connection/3/5</em> - one of these operations is invoked + when a client side ORB tries to set up a connection to the target ORB. + If an interceptor exports both versions, arity 3 and 5, which + operation that will be invoked is Orber internal.</item> + <item><em>out_request/6</em> - supplies all request data on the client side + ORB.</item> + <item><em>out_request_encoded/6</em> - similar to <c>out_request</c> + but the request body is encode.</item> + <item><em>in_request_encoded/6</em> - after a new request arrives at the + target ORB the request data is passed to the interceptor in + encoded format.</item> + <item><em>in_request/6</em> - prior to invoking the operation on the + target object, the interceptor <c>in_request</c> is called.</item> + <item><em>out_reply/6</em> - after the target object replied the + <c>out_reply</c> operation is called with the result of the object + invocation.</item> + <item><em>out_reply_encoded/6</em> - before sending a reply back to the + client side ORB this operation is called with the result in + encoded format.</item> + <item><em>in_reply_encoded/6</em> - after the client side ORB receives + a reply this function is called with the reply in encoded + format.</item> + <item><em>in_reply/6</em> - before delivering the reply to the client + this operation is invoked.</item> + <item><em>closed_in_connection/1</em> - when a connection is terminated + on the client side this function is called.</item> + <item><em>closed_out_connection/1</em> - if an outgoing connection is + terminated this operation will be invoked.</item> + </list> + <p>The operations <c>new_out_connection</c>, <c>new_in_connection</c>, + <c>closed_in_connection</c> and <c>closed_out_connection</c> operations + are only invoked <em>once</em> per connection. The remaining operations + are called, as shown below, for every Request/Reply to/from remote + CORBA Objects.</p> + <marker id="interceptor_operations"></marker> + <image file="interceptor_operations.gif"> + <icaption> +The Invocation Order of Interceptor Functions.</icaption> + </image> + </section> + </section> + + <section> + <title>Interceptor Example</title> + <p>Assume we want to create a simple access service which purpose is to:</p> + <list type="bulleted"> + <item>Only allow incoming request from ORB's residing on a certain set of + nodes.</item> + <item>Restrict the objects any client may invoke operations on.</item> + <item>Only allow outgoing requests to call a limited set of external + ORB's.</item> + <item>Add a checksum to each binary request/reply body.</item> + </list> + <p>To restricts the access we use a <c>protected</c> and <c>named</c> ets-table + holding all information. How the ets-table is initiated and maintained + is implementation specific, but it contain + <c>{Node, ObjectTable, ChecksumModule}</c> where <c>Node</c> is used as + ets-key, <c>ObjectTable</c> is a reference to another ets-table in which + we store which objects the clients are allowed to invoke operations on + and <c>ChecksumModule</c> determines which module we should use to handle + the checksums. </p> + <code type="none"> +new_in_connection(Arg, Host, Port) -> + %% Since we only use one interceptor we do not care about the + %% input Arg since it is set do undefined by Orber. + case ets:lookup(in_access_table, Host) of + [] -> + %% We may want to log the Host/Port to see if someone tried + %% to hack in to our system. + exit("Access not granted"); + [{Host, ObjTable, ChecksumModule}] -> + {ObjTable, ChecksumModule} + end. + </code> + <p>The returned tuple, i.e., {ObjTable, ChecksumModule}, will be passed + as the first argument whenever invoking one of the interceptor functions. + Unless the connection attempt did not fail we are now ready for receiving + requests from the client side ORB.</p> + <p>When a new request comes in the first interceptor function to be invoked is + <c>in_request_encoded</c>. We will remove the checksum from the coded + request body in the following way:</p> + <code type="none"> +in_request_encoded({ObjTable, ChecksumModule}, ObjKey, Ctx, Op, Bin, Extra) -> + NewBin = ChecksumModule:remove_checksum(Bin), + {NewBin, Extra}. + </code> + <p>If the checksum check fails the <c>ChecksumModule</c> should invoke exit/1. + But if the check succeeded we are now ready to check if the client-ORB + objects are allowed to invoke operations on the target object. Please note, + it is possible to run both checks in <c>in_request_encoded</c>. Please + note, the checksum calculation must be relatively fast to ensure a + good throughput.</p> + <p>If we want to we can restrict any clients to only use a subset of operations + exported by a server:</p> + <code type="none"> +in_request({ObjTable, ChecksumModule}, ObjKey, Ctx, Op, Params, Extra) -> + case ets:lookup(ObjTable, {ObjKey, Op}) of + [] -> + exit("Client tried to invoke illegal operation"); + [SomeData] -> + {Params, Extra} + end. + </code> + <p>At this point Orber are now ready to invoke the operation on the target + object. Since we do not care about what the reply is the <c>out_reply</c> + function do nothing, i.e.:</p> + <code type="none"> +out_reply(_, _, _, _, Reply, Extra) -> + {Reply, Extra}. + </code> + <p>If the client side ORB expects a checksum to be added to the reply we + add it by using:</p> + <code type="none"> +out_reply_encoded({ObjTable, ChecksumModule}, ObjKey, Ctx, Op, Bin, Extra) -> + NewBin = ChecksumModule:add_checksum(Bin), + {NewBin, Extra}. + </code> + <warning> + <p>If we manipulate the binary as above the behavior <em>must</em> + be <c>Bin == remove_checksum(add_checksum(Bin))</c>.</p> + </warning> + <p>For outgoing requests the principle is the same. Hence, it is not further + described here. The complete interceptor module would look like:</p> + <code type="none"> + +-module(myInterceptor). + +%% Interceptor functions. +-export([new_out_connection/3, +\011 new_in_connection/3, +\011 closed_in_connection/1, +\011 closed_out_connection/1, +\011 in_request_encoded/6, +\011 in_reply_encoded/6, +\011 out_reply_encoded/6, +\011 out_request_encoded/6, +\011 in_request/6, +\011 in_reply/6, +\011 out_reply/6, +\011 out_request/6]). + +new_in_connection(Arg, Host, Port) -> + %% Since we only use one interceptor we do not care about the + %% input Arg since it is set do undefined by Orber. + case ets:lookup(in_access_table, Host) of + [] -> + %% We may want to log the Host/Port to see if someone tried + %% to hack in to our system. + exit("Access not granted"); + [{Host, ObjTable, ChecksumModule}] -> + {ObjTable, ChecksumModule} + end. + +new_out_connection(Arg, Host, Port) -> + case ets:lookup(out_access_table, Host) of + [] -> + exit("Access not granted"); + [{Host, ObjTable, ChecksumModule}] -> + {ObjTable, ChecksumModule} + end. + +in_request_encoded({_, ChecksumModule}, ObjKey, Ctx, Op, Bin, Extra) -> + NewBin = ChecksumModule:remove_checksum(Bin), + {NewBin, Extra}. + +in_request({ObjTable, _}, ObjKey, Ctx, Op, Params, Extra) -> + case ets:lookup(ObjTable, {ObjKey, Op}) of + [] -> + exit("Client tried to invoke illegal operation"); + [SomeData] -> + {Params, Extra} + end. + +out_reply(_, _, _, _, Reply, Extra) -> + {Reply, Extra}. + +out_reply_encoded({_, ChecksumModule}, ObjKey, Ctx, Op, Bin, Extra) -> + NewBin = ChecksumModule:add_checksum(Bin), + {NewBin, Extra}. + +out_request({ObjTable, _}, ObjKey, Ctx, Op, Params, Extra) -> + case ets:lookup(ObjTable, {ObjKey, Op}) of + [] -> + exit("Client tried to invoke illegal operation"); + [SomeData] -> + {Params, Extra} + end. + +out_request_encoded({_, ChecksumModule}, ObjKey, Ctx, Op, Bin, Extra) -> + NewBin = ChecksumModule:add_checksum(Bin), + {NewBin, Extra}. + +in_reply_encoded({_, ChecksumModule}, ObjKey, Ctx, Op, Bin, Extra) -> + NewBin = ChecksumModule:remove_checksum(Bin), + {NewBin, Extra}. + +in_reply(_, _, _, _, Reply, Extra) -> + {Reply, Extra}. + +closed_in_connection(Arg) -> + %% Nothing to clean up. + Arg. + +closed_out_connection(Arg) -> + %% Nothing to clean up. + Arg. + </code> + <note> + <p>One can also use interceptors for debugging purposes, e.g., + print which objects and operations are invoked with which arguments + and the outcome of the operation. In conjunction with the configuration + parameter <c>orber_debug_level</c> it is rather easy to find out what + went wrong or just to log the traffic. </p> + </note> + </section> +</chapter> + |