1
<?xml version="1.0" encoding="latin1" ?>
2
<!DOCTYPE chapter SYSTEM "chapter.dtd">
9
<holder>Ericsson AB, All Rights Reserved</holder>
12
The contents of this file are subject to the Erlang Public License,
13
Version 1.1, (the "License"); you may not use this file except in
14
compliance with the License. You should have received a copy of the
15
Erlang Public License along with this software. If not, it can be
16
retrieved online at http://www.erlang.org/.
18
Software distributed under the License is distributed on an "AS IS"
19
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
20
the License for the specific language governing rights and limitations
23
The Initial Developer of the Original Code is Ericsson AB.
26
<title>Orber Interceptors</title>
27
<prepared>Nick</prepared>
29
<date>2001-08-16</date>
34
<title>Using Interceptors</title>
35
<p>For Inter-ORB communication, e.g., via <c>IIOP</c>, it is possible
36
to intercept requests and replies. To be able to use <c>Interceptors</c>
37
Orber the configuration parameter <c>interceptors</c> must be defined.</p>
40
<title>Configure Orber to Use Interceptors</title>
41
<p>The configuration parameter <c>interceptors</c> must be defined, e.g.,
42
as command line option:</p>
44
erl -orber interceptors "{native, ['myInterceptor']}"
46
<p>It is possible to use more than one interceptor; simply add them to the
47
list and they will be invoked in the same order as they appear in the list.</p>
48
<p>One can also active and deactivate an interceptor during
49
run-time, but this will only affect currently existing connections.
50
For more information, consult Orber's Reference Manual regarding the
51
operations <c>orber:activate_audit_trail/0/1</c> and
52
<c>orber:activate_audit_trail/0/1.</c></p>
56
<title>Creating Interceptors</title>
57
<p>Each supplied interceptor <em>must</em> export the following functions:</p>
58
<list type="bulleted">
59
<item><em>new_out_connection/3/5</em> - one of these operations is called when
60
a client application calls an object residing on remote ORB.
61
If an interceptor exports both versions, arity 3 and 5, which
62
operation that will be invoked is Orber internal.</item>
63
<item><em>new_in_connection/3/5</em> - one of these operations is invoked
64
when a client side ORB tries to set up a connection to the target ORB.
65
If an interceptor exports both versions, arity 3 and 5, which
66
operation that will be invoked is Orber internal.</item>
67
<item><em>out_request/6</em> - supplies all request data on the client side
69
<item><em>out_request_encoded/6</em> - similar to <c>out_request</c>
70
but the request body is encode.</item>
71
<item><em>in_request_encoded/6</em> - after a new request arrives at the
72
target ORB the request data is passed to the interceptor in
73
encoded format.</item>
74
<item><em>in_request/6</em> - prior to invoking the operation on the
75
target object, the interceptor <c>in_request</c> is called.</item>
76
<item><em>out_reply/6</em> - after the target object replied the
77
<c>out_reply</c> operation is called with the result of the object
79
<item><em>out_reply_encoded/6</em> - before sending a reply back to the
80
client side ORB this operation is called with the result in
81
encoded format.</item>
82
<item><em>in_reply_encoded/6</em> - after the client side ORB receives
83
a reply this function is called with the reply in encoded
85
<item><em>in_reply/6</em> - before delivering the reply to the client
86
this operation is invoked.</item>
87
<item><em>closed_in_connection/1</em> - when a connection is terminated
88
on the client side this function is called.</item>
89
<item><em>closed_out_connection/1</em> - if an outgoing connection is
90
terminated this operation will be invoked.</item>
92
<p>The operations <c>new_out_connection</c>, <c>new_in_connection</c>,
93
<c>closed_in_connection</c> and <c>closed_out_connection</c> operations
94
are only invoked <em>once</em> per connection. The remaining operations
95
are called, as shown below, for every Request/Reply to/from remote
97
<marker id="interceptor_operations"></marker>
98
<image file="interceptor_operations">
100
The Invocation Order of Interceptor Functions.</icaption>
106
<title>Interceptor Example</title>
107
<p>Assume we want to create a simple access service which purpose is to:</p>
108
<list type="bulleted">
109
<item>Only allow incoming request from ORB's residing on a certain set of
111
<item>Restrict the objects any client may invoke operations on.</item>
112
<item>Only allow outgoing requests to call a limited set of external
114
<item>Add a checksum to each binary request/reply body.</item>
116
<p>To restricts the access we use a <c>protected</c> and <c>named</c> ets-table
117
holding all information. How the ets-table is initiated and maintained
118
is implementation specific, but it contain
119
<c>{Node, ObjectTable, ChecksumModule}</c> where <c>Node</c> is used as
120
ets-key, <c>ObjectTable</c> is a reference to another ets-table in which
121
we store which objects the clients are allowed to invoke operations on
122
and <c>ChecksumModule</c> determines which module we should use to handle
125
new_in_connection(Arg, Host, Port) ->
126
%% Since we only use one interceptor we do not care about the
127
%% input Arg since it is set do undefined by Orber.
128
case ets:lookup(in_access_table, Host) of
130
%% We may want to log the Host/Port to see if someone tried
131
%% to hack in to our system.
132
exit("Access not granted");
133
[{Host, ObjTable, ChecksumModule}] ->
134
{ObjTable, ChecksumModule}
137
<p>The returned tuple, i.e., {ObjTable, ChecksumModule}, will be passed
138
as the first argument whenever invoking one of the interceptor functions.
139
Unless the connection attempt did not fail we are now ready for receiving
140
requests from the client side ORB.</p>
141
<p>When a new request comes in the first interceptor function to be invoked is
142
<c>in_request_encoded</c>. We will remove the checksum from the coded
143
request body in the following way:</p>
145
in_request_encoded({ObjTable, ChecksumModule}, ObjKey, Ctx, Op, Bin, Extra) ->
146
NewBin = ChecksumModule:remove_checksum(Bin),
149
<p>If the checksum check fails the <c>ChecksumModule</c> should invoke exit/1.
150
But if the check succeeded we are now ready to check if the client-ORB
151
objects are allowed to invoke operations on the target object. Please note,
152
it is possible to run both checks in <c>in_request_encoded</c>. Please
153
note, the checksum calculation must be relatively fast to ensure a
155
<p>If we want to we can restrict any clients to only use a subset of operations
156
exported by a server:</p>
158
in_request({ObjTable, ChecksumModule}, ObjKey, Ctx, Op, Params, Extra) ->
159
case ets:lookup(ObjTable, {ObjKey, Op}) of
161
exit("Client tried to invoke illegal operation");
166
<p>At this point Orber are now ready to invoke the operation on the target
167
object. Since we do not care about what the reply is the <c>out_reply</c>
168
function do nothing, i.e.:</p>
170
out_reply(_, _, _, _, Reply, Extra) ->
173
<p>If the client side ORB expects a checksum to be added to the reply we
176
out_reply_encoded({ObjTable, ChecksumModule}, ObjKey, Ctx, Op, Bin, Extra) ->
177
NewBin = ChecksumModule:add_checksum(Bin),
181
<p>If we manipulate the binary as above the behavior <em>must</em>
182
be <c>Bin == remove_checksum(add_checksum(Bin))</c>.</p>
184
<p>For outgoing requests the principle is the same. Hence, it is not further
185
described here. The complete interceptor module would look like:</p>
188
-module(myInterceptor).
190
%% Interceptor functions.
191
-export([new_out_connection/3,
192
\011 new_in_connection/3,
193
\011 closed_in_connection/1,
194
\011 closed_out_connection/1,
195
\011 in_request_encoded/6,
196
\011 in_reply_encoded/6,
197
\011 out_reply_encoded/6,
198
\011 out_request_encoded/6,
202
\011 out_request/6]).
204
new_in_connection(Arg, Host, Port) ->
205
%% Since we only use one interceptor we do not care about the
206
%% input Arg since it is set do undefined by Orber.
207
case ets:lookup(in_access_table, Host) of
209
%% We may want to log the Host/Port to see if someone tried
210
%% to hack in to our system.
211
exit("Access not granted");
212
[{Host, ObjTable, ChecksumModule}] ->
213
{ObjTable, ChecksumModule}
216
new_out_connection(Arg, Host, Port) ->
217
case ets:lookup(out_access_table, Host) of
219
exit("Access not granted");
220
[{Host, ObjTable, ChecksumModule}] ->
221
{ObjTable, ChecksumModule}
224
in_request_encoded({_, ChecksumModule}, ObjKey, Ctx, Op, Bin, Extra) ->
225
NewBin = ChecksumModule:remove_checksum(Bin),
228
in_request({ObjTable, _}, ObjKey, Ctx, Op, Params, Extra) ->
229
case ets:lookup(ObjTable, {ObjKey, Op}) of
231
exit("Client tried to invoke illegal operation");
236
out_reply(_, _, _, _, Reply, Extra) ->
239
out_reply_encoded({_, ChecksumModule}, ObjKey, Ctx, Op, Bin, Extra) ->
240
NewBin = ChecksumModule:add_checksum(Bin),
243
out_request({ObjTable, _}, ObjKey, Ctx, Op, Params, Extra) ->
244
case ets:lookup(ObjTable, {ObjKey, Op}) of
246
exit("Client tried to invoke illegal operation");
251
out_request_encoded({_, ChecksumModule}, ObjKey, Ctx, Op, Bin, Extra) ->
252
NewBin = ChecksumModule:add_checksum(Bin),
255
in_reply_encoded({_, ChecksumModule}, ObjKey, Ctx, Op, Bin, Extra) ->
256
NewBin = ChecksumModule:remove_checksum(Bin),
259
in_reply(_, _, _, _, Reply, Extra) ->
262
closed_in_connection(Arg) ->
263
%% Nothing to clean up.
266
closed_out_connection(Arg) ->
267
%% Nothing to clean up.
271
<p>One can also use interceptors for debugging purposes, e.g.,
272
print which objects and operations are invoked with which arguments
273
and the outcome of the operation. In conjunction with the configuration
274
parameter <c>orber_debug_level</c> it is rather easy to find out what
275
went wrong or just to log the traffic. </p>