[omniORB] Security/Authentication
JHJE (Jan Holst Jensen)
jhje@novonordisk.com
Thu Feb 27 13:21:02 2003
> Can you post an example of how you do this? It sounds interesting.
Sure. Although this code is in Object Pascal, it should be general enough
CORBA-wise to translate well to C++. "High(sc.context_data) + 1" returns the
length of a service context octet sequence, and "Move(....)" is a mem -> mem
copy function.
This is still a work in progress, but I have the authenticator running and
the interceptors shown here work fine. The authentication service has an IDL
like
interface authenticator {
boolean authenticate(in string user_name, in string password, out long
session_token);
boolean is_valid_session_token(in string user_name, in long
session_token);
};
Register a client request interceptor and have it piggy-back user name and
session token onto IIOP messages after having called the authenticator
interface and getting a session_token in return:
const
// Both client and server must agree on the service request IDs used.
USERNAME_CTXID = 100;
SESSION_CTXID = 101;
var
// Client sets UserName and gets SessionToken from authenticator service.
UserName: String;
SessionToken: Integer;
procedure TMyClientInterceptor.send_request(const ri: IClientRequestInfo);
var
sc: ServiceContext;
begin
sc.context_id := USERNAME_CTXID;
// Allocate service request context data buffer.
SetLength(sc.context_data, Length(UserName));
// Copy string data to service context buffer.
Move(UserName[1], sc.context_data[0], Length(UserName));
ri.add_request_service_context(sc, false);
sc.context_id := SESSION_CTXID;
SetLength(sc.context_data, SizeOf(SessionToken));
Move(SessionToken, sc.context_data[0], SizeOf(SessionToken));
ri.add_request_service_context(sc, false);
end;
On the server side, register a server request interceptor and do:
procedure TMyServerInterceptor.receive_request_service_contexts(const ri:
IServerRequestInfo);
var
sc: ServiceContext;
UserName: String;
SessionToken: Integer;
begin
UserName := '';
SessionToken := -1;
try
sc := ri.get_request_service_context(USERNAME_CTXID);
{ Allocate string buffer based on length of service context octet
sequence. }
SetLength(UserName, High(sc.context_data) + 1);
Move(sc.context_data[0], UserName[1], High(sc.context_data) + 1);
Writeln('User name "', UserName, '".');
except
on E: BAD_PARAM do
writeln(E.ClassName, ': No user name embedded in request.');
end;
try
sc := ri.get_request_service_context(SESSION_CTXID);
// Potential Access Violation lurking here if sc.context_data is not at
least
// 4 bytes long, so use min() function.
Move(sc.context_data[0], SessionToken,
min(SizeOf(SessionToken), High(sc.context_data) + 1));
Writeln(' with session token ', SessionToken);
except
on E: BAD_PARAM do
writeln(E.ClassName, ': No session token embedded in request.');
end;
// Do access check using is_valid_session_token, raise
CORBA::NO_PERMISSION if it fails.
end;
Remaining issues:
* I suppose I should encode/decode the UserName string so it transfers well
between different architectures and platforms.
* Same goes for SessionToken, at least making sure that it it encoded like a
CORBA::long is encoded in an IIOP message.
* The session token is really a password proxy in this respect so you must
keep it secret (use e.g. SSL) and have it time out some way.
I assume these issues would be readily solved by buying a CORBA security
service, but so far I found the security service docs a bit overwhelming so
I just threw this code together. At least it gave me a good grip on the
issues involved.
Has anyone tried embedding a Kerberos ticket like this ? Could that be used
by the server to impersonate the client (really useful for database-apps) ?
-- Jan