package org.jacorb.security.sas;
/*
* JacORB - a free Java ORB
*
* Copyright (C) 2000-2004 Nicolas Noffke, Gerald Brose.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
import java.net.URLDecoder;
import java.util.Hashtable;
import org.jacorb.config.*;
import org.slf4j.Logger;
import org.jacorb.orb.CDRInputStream;
import org.jacorb.orb.MinorCodes;
import org.jacorb.orb.giop.ClientConnection;
import org.jacorb.orb.portableInterceptor.ClientRequestInfoImpl;
import org.omg.ATLAS.ATLASProfile;
import org.omg.ATLAS.ATLASProfileHelper;
import org.omg.ATLAS.AuthTokenData;
import org.omg.ATLAS.AuthTokenDispenser;
import org.omg.ATLAS.AuthTokenDispenserHelper;
import org.omg.ATLAS.SCS_ATLAS;
import org.omg.CORBA.Any;
import org.omg.CORBA.BAD_PARAM;
import org.omg.CORBA.CompletionStatus;
import org.omg.CSI.AuthorizationElement;
import org.omg.CSI.CompleteEstablishContext;
import org.omg.CSI.ContextError;
import org.omg.CSI.EstablishContext;
import org.omg.CSI.IdentityToken;
import org.omg.CSI.MTCompleteEstablishContext;
import org.omg.CSI.MTContextError;
import org.omg.CSI.MessageInContext;
import org.omg.CSI.SASContextBody;
import org.omg.CSI.SASContextBodyHelper;
import org.omg.CSIIOP.CompoundSecMechList;
import org.omg.CSIIOP.CompoundSecMechListHelper;
import org.omg.CSIIOP.ServiceConfiguration;
import org.omg.CSIIOP.TAG_CSI_SEC_MECH_LIST;
import org.omg.IOP.Codec;
import org.omg.IOP.ENCODING_CDR_ENCAPS;
import org.omg.IOP.Encoding;
import org.omg.IOP.ServiceContext;
import org.omg.IOP.TaggedComponent;
import org.omg.IOP.CodecFactoryPackage.UnknownEncoding;
import org.omg.PortableInterceptor.ClientRequestInterceptor;
import org.omg.PortableInterceptor.ORBInitInfo;
/**
* This is the SAS Client Security Service (CSS) Interceptor
*
* @author David Robison
* @version $Id: SASClientInterceptor.java,v 1.28 2009-05-03 21:36:48 andre.spiegel Exp $
*/
public class SASClientInterceptor
extends org.omg.CORBA.LocalObject
implements ClientRequestInterceptor, Configurable
{
protected static final int SecurityAttributeService = 15;
protected final String DEFAULT_NAME = "SASClientInterceptor";
protected Codec codec = null;
protected String name = null;
private Logger logger = null;
protected byte[] contextToken = new byte[0];
protected boolean useStateful = true;
protected Hashtable atlasCache = new Hashtable();
protected ISASContext sasContext = null;
public SASClientInterceptor(ORBInitInfo info)
throws UnknownEncoding, ConfigurationException
{
name = DEFAULT_NAME;
Encoding encoding = new Encoding(ENCODING_CDR_ENCAPS.value, (byte) 1, (byte) 0);
codec = info.codec_factory().create_codec(encoding);
org.jacorb.orb.ORB orb =
((org.jacorb.orb.portableInterceptor.ORBInitInfoImpl)info).getORB ();
configure( orb.getConfiguration());
}
public void configure(Configuration configuration)
throws ConfigurationException
{
logger =
((org.jacorb.config.Configuration)configuration).getLogger("jacorb.security.sas.CSS");
useStateful =
configuration.getAttribute("jacorb.security.sas.stateful","true").equals("true");
String contextClass = null;
try
{
contextClass = configuration.getAttribute("jacorb.security.sas.contextClass");
Class c =
org.jacorb.util.ObjectUtil.classForName(contextClass);
sasContext = (ISASContext)c.newInstance();
}
catch(ConfigurationException ce)
{
if (logger.isDebugEnabled())
logger.debug("ConfigurationException", ce);
}
catch (Exception e)
{
if (logger.isErrorEnabled())
logger.error("Could not instantiate class " + contextClass + ": " + e);
}
if (sasContext == null)
{
if (logger.isErrorEnabled())
logger.error("Could not load SAS context class: "+contextClass);
}
else
{
sasContext.configure(configuration);
sasContext.initClient();
}
}
public void setContextToken(byte[] contextToken) {
this.contextToken = contextToken;
}
public String name()
{
return name;
}
public void destroy()
{
}
public void send_request(org.omg.PortableInterceptor.ClientRequestInfo ri)
throws org.omg.PortableInterceptor.ForwardRequest
{
//if (ri.operation().equals("_is_a")) return;
//if (ri.operation().equals("_non_existent")) return;
org.omg.CORBA.ORB orb = ((ClientRequestInfoImpl) ri).orb;
// see if target requires protected requests by looking into the IOR
CompoundSecMechList csmList = null;
try
{
TaggedComponent tc = ri.get_effective_component(TAG_CSI_SEC_MECH_LIST.value);
CDRInputStream is = new CDRInputStream( (org.omg.CORBA.ORB)null, tc.component_data);
is.openEncapsulatedArray();
csmList = CompoundSecMechListHelper.read( is );
}
catch (BAD_PARAM e)
{
if (logger.isDebugEnabled())
logger.debug("Did not find tagged component TAG_CSI_SEC_MECH_LIST: "+
ri.operation());
}
catch (Exception e)
{
if (logger.isWarnEnabled())
logger.warn("Did not find tagged component TAG_CSI_SEC_MECH_LIST: "+e);
}
if(csmList != null &&
csmList.mechanism_list[0].as_context_mech.target_supports == 0 &&
csmList.mechanism_list[0].as_context_mech.target_requires == 0 &&
csmList.mechanism_list[0].sas_context_mech.target_supports == 0 &&
csmList.mechanism_list[0].sas_context_mech.target_requires == 0) {
return;
}
// ask connection for client_context_id
ClientConnection connection = ((ClientRequestInfoImpl) ri).connection;
long client_context_id = 0;
if (useStateful)
client_context_id = connection.cacheSASContext("css".getBytes());
if (client_context_id < 0)
{
if (logger.isInfoEnabled())
logger.info("New SAS Context: " + (-client_context_id));
}
// get ATLAS tokens
AuthorizationElement[] authorizationList = csmList != null
? getATLASTokens(orb, csmList)
: new AuthorizationElement[0];
// establish the security context
try
{
Any msg = null;
if (client_context_id <= 0)
{
IdentityToken identityToken = new IdentityToken();
identityToken.absent(true);
contextToken = sasContext.createClientContext(orb, codec, csmList);
msg = makeEstablishContext(orb,
-client_context_id,
authorizationList,
identityToken,
contextToken);
}
else
{
msg = makeMessageInContext(orb, client_context_id, false);
}
ri.add_request_service_context(new ServiceContext(SecurityAttributeService, codec.encode_value( msg ) ), true);
}
catch (Exception e)
{
if (logger.isWarnEnabled())
logger.warn("Could not set security service context: " + e);
throw new org.omg.CORBA.NO_PERMISSION("SAS Could not set security service context: " + e,
MinorCodes.SAS_CSS_FAILURE,
CompletionStatus.COMPLETED_NO);
}
}
public void send_poll(org.omg.PortableInterceptor.ClientRequestInfo ri)
{
}
public void receive_reply(org.omg.PortableInterceptor.ClientRequestInfo ri)
{
// get SAS message
SASContextBody contextBody = null;
ServiceContext ctx = null;
try
{
ctx = ri.get_reply_service_context(SecurityAttributeService);
}
catch (BAD_PARAM e)
{
if (logger.isDebugEnabled())
logger.debug("No SAS security context found: "+ri.operation());
}
catch (Exception e)
{
if (logger.isWarnEnabled())
logger.warn("No SAS security context found: "+e);
}
if (ctx == null || ctx.context_data.length <= 1) return;
try
{
Any msg = codec.decode_value( ctx.context_data, SASContextBodyHelper.type() );
contextBody = SASContextBodyHelper.extract(msg);
}
catch (Exception e)
{
if (logger.isWarnEnabled())
logger.warn("Could not parse SAS reply: " + e);e.printStackTrace();
throw new org.omg.CORBA.NO_PERMISSION("SAS Could not parse SAS reply: " + e,
MinorCodes.SAS_CSS_FAILURE,
CompletionStatus.COMPLETED_MAYBE);
}
ClientConnection connection = ((ClientRequestInfoImpl) ri).connection;
// process CompleteEstablishContext message
if (contextBody.discriminator() == MTCompleteEstablishContext.value)
{
CompleteEstablishContext reply = contextBody.complete_msg();
// if not stateful, remove from connection
if (reply.client_context_id > 0 && !reply.context_stateful)
connection.purgeSASContext(reply.client_context_id);
}
// process ContextError message
if (contextBody.discriminator() == MTContextError.value)
{
ContextError reply = contextBody.error_msg();
// if stateful, remove from connection
if (reply.client_context_id > 0)
connection.purgeSASContext(reply.client_context_id);
}
}
public void receive_exception(org.omg.PortableInterceptor.ClientRequestInfo ri)
throws org.omg.PortableInterceptor.ForwardRequest
{
// get SAS message
SASContextBody contextBody = null;
ServiceContext ctx = null;
try
{
ctx = ri.get_reply_service_context(SecurityAttributeService);
}
catch (BAD_PARAM e)
{
if (logger.isDebugEnabled())
logger.debug("No SAS security context found (exception): "+ri.operation());
}
catch (Exception e)
{
if (logger.isWarnEnabled())
logger.warn("No SAS security context found (exception): "+e);
}
if (ctx == null || ctx.context_data.length <= 1) return;
try
{
Any msg = codec.decode_value( ctx.context_data, SASContextBodyHelper.type() );
contextBody = SASContextBodyHelper.extract(msg);
}
catch (Exception e)
{
if (logger.isWarnEnabled())
logger.warn("Could not parse SAS reply: " + e);
throw new org.omg.CORBA.NO_PERMISSION("SAS Could not parse SAS reply: " + e,
MinorCodes.SAS_CSS_FAILURE,
CompletionStatus.COMPLETED_MAYBE);
}
ClientConnection connection = ((ClientRequestInfoImpl) ri).connection;
// process CompleteEstablishContext message
if (contextBody.discriminator() == MTCompleteEstablishContext.value)
{
CompleteEstablishContext reply = contextBody.complete_msg();
logger.debug("receive_exception MTCompleteEstablishContext: " + reply.client_context_id);
// if not stateful, remove from connection
if (reply.client_context_id > 0 && !reply.context_stateful)
connection.purgeSASContext(reply.client_context_id);
}
// process ContextError message
if (contextBody.discriminator() == MTContextError.value)
{
ContextError reply = contextBody.error_msg();
logger.debug("receive_exception MTContextError: " + reply.client_context_id);
// if stateful, remove from connection
if (reply.client_context_id > 0)
connection.purgeSASContext(reply.client_context_id);
// if context not found, resend with empty context cache
if (reply.major_status == 2) throw new org.omg.PortableInterceptor.ForwardRequest(ri.target());
}
}
public void receive_other(org.omg.PortableInterceptor.ClientRequestInfo ri)
throws org.omg.PortableInterceptor.ForwardRequest
{
}
protected Any makeEstablishContext(org.omg.CORBA.ORB orb,
long client_context_id,
AuthorizationElement[] authorization_token,
IdentityToken identity_token,
byte[] client_authentication_token)
{
EstablishContext msg = new EstablishContext();
msg.client_context_id = client_context_id;
msg.client_authentication_token = client_authentication_token;
msg.identity_token = identity_token;
msg.authorization_token = authorization_token;
SASContextBody contextBody = new SASContextBody();
contextBody.establish_msg(msg);
Any any = orb.create_any();
SASContextBodyHelper.insert( any, contextBody );
return any;
}
protected Any makeMessageInContext(org.omg.CORBA.ORB orb,
long client_context_id,
boolean discard_context)
{
MessageInContext msg = new MessageInContext();
msg.client_context_id = client_context_id;
msg.discard_context = discard_context;
SASContextBody contextBody = new SASContextBody();
contextBody.in_context_msg(msg);
Any any = orb.create_any();
SASContextBodyHelper.insert( any, contextBody );
return any;
}
protected AuthorizationElement[] getATLASTokens(org.omg.CORBA.ORB orb,
CompoundSecMechList csmList)
throws org.omg.CORBA.NO_PERMISSION
{
// find the ATLAS profile in the IOR
ATLASProfile atlasProfile = null;
try
{
ServiceConfiguration authorities[] =
csmList.mechanism_list[0].sas_context_mech.privilege_authorities;
for (int i = 0; i < authorities.length; i++)
{
if (authorities[i].syntax != SCS_ATLAS.value)
continue;
Any any = codec.decode(authorities[i].name);
atlasProfile = ATLASProfileHelper.extract(any);
}
}
catch (Exception e)
{
if (logger.isWarnEnabled())
logger.warn("Error parsing ATLAS from IOR: " + e);
throw new org.omg.CORBA.NO_PERMISSION("SAS Error parsing ATLAS from IOR: " + e,
MinorCodes.SAS_ATLAS_FAILURE,
CompletionStatus.COMPLETED_NO);
}
if (atlasProfile == null)
return new AuthorizationElement[0];
String cacheID = new String(atlasProfile.the_cache_id);
String locator = atlasProfile.the_locator.the_url();
if (locator != null)
locator = URLDecoder.decode(locator);
// see if the tokens are in the ATLAS cache
synchronized (atlasCache)
{
if (atlasCache.containsKey(cacheID))
{
return ((AuthTokenData)atlasCache.get(cacheID)).auth_token;
}
}
// contact the ATLAS server and get the credentials
AuthTokenDispenser dispenser = null;
try
{
org.omg.CORBA.Object obj = orb.string_to_object(locator);
dispenser = AuthTokenDispenserHelper.narrow(obj);
}
catch (Exception e)
{
logger.warn("Could not find ATLAS server " + locator + ": " + e);
throw new org.omg.CORBA.NO_PERMISSION("SAS Could not find ATLAS server " + locator + ": " + e, MinorCodes.SAS_ATLAS_FAILURE, CompletionStatus.COMPLETED_NO);
}
if (dispenser == null)
{
if (logger.isWarnEnabled())
logger.warn("SAS found null ATLAS server " + locator);
throw new org.omg.CORBA.NO_PERMISSION("SAS found null ATLAS server "+locator,
MinorCodes.SAS_ATLAS_FAILURE,
CompletionStatus.COMPLETED_NO);
}
AuthTokenData data = null;
try
{
data = dispenser.get_my_authorization_token();
}
catch (Exception e)
{
if (logger.isWarnEnabled())
logger.warn("Error getting ATLAS tokens from server " +
locator + ": " + e);
throw new org.omg.CORBA.NO_PERMISSION("SAS Error getting ATLAS tokens from server: " + e,
MinorCodes.SAS_ATLAS_FAILURE,
CompletionStatus.COMPLETED_NO);
}
synchronized (atlasCache)
{
atlasCache.put(cacheID, data);
}
return data.auth_token;
}
}