package org.jacorb.security.sas;
/*
* JacORB - a free Java ORB
*
* Copyright (C) 2000-2014 Gerald Brose / The JacORB Team.
*
* 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.util.Hashtable;
import org.jacorb.config.Configurable;
import org.jacorb.config.Configuration;
import org.jacorb.config.ConfigurationException;
import org.jacorb.orb.MinorCodes;
import org.jacorb.orb.giop.GIOPConnection;
import org.jacorb.orb.portableInterceptor.ServerRequestInfoImpl;
import org.jacorb.sasPolicy.ATLASPolicy;
import org.jacorb.sasPolicy.ATLASPolicyValues;
import org.jacorb.sasPolicy.ATLAS_POLICY_TYPE;
import org.jacorb.sasPolicy.SASPolicy;
import org.jacorb.sasPolicy.SASPolicyValues;
import org.jacorb.sasPolicy.SAS_POLICY_TYPE;
import org.omg.CORBA.Any;
import org.omg.CORBA.BAD_PARAM;
import org.omg.CORBA.CompletionStatus;
import org.omg.CORBA.Policy;
import org.omg.CORBA.portable.ObjectImpl;
import org.omg.CSI.CompleteEstablishContext;
import org.omg.CSI.ContextError;
import org.omg.CSI.EstablishContext;
import org.omg.CSI.MTEstablishContext;
import org.omg.CSI.MTMessageInContext;
import org.omg.CSI.MessageInContext;
import org.omg.CSI.SASContextBody;
import org.omg.CSI.SASContextBodyHelper;
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.CodecFactoryPackage.UnknownEncoding;
import org.omg.PortableInterceptor.ForwardRequest;
import org.omg.PortableInterceptor.ORBInitInfo;
import org.omg.PortableInterceptor.ServerRequestInfo;
import org.omg.PortableInterceptor.ServerRequestInterceptor;
import org.slf4j.Logger;
/**
* This is the SAS Target Security Service (TSS) Interceptor
*
* @author David Robison
*/
public class SASTargetInterceptor
extends org.omg.CORBA.LocalObject
implements ServerRequestInterceptor, Configurable
{
private static final String name = "SASTargetInterceptor";
private Logger logger = null;
protected org.jacorb.orb.ORB orb = null;
protected Codec codec = null;
protected int sasReplySlotID = -1;
protected int clientUserNameSlotID = -1;
protected int sasContextsCubby = -1;
protected boolean useSsl = false;
protected ISASContext sasContext = null;
public SASTargetInterceptor(ORBInitInfo info)
throws UnknownEncoding, ConfigurationException
{
sasReplySlotID = info.allocate_slot_id();
sasContextsCubby = org.jacorb.orb.giop.GIOPConnection.allocate_cubby_id();
Encoding encoding =
new Encoding(ENCODING_CDR_ENCAPS.value, (byte) 1, (byte) 0);
codec =
info.codec_factory().create_codec(encoding);
orb = ((org.jacorb.orb.portableInterceptor.ORBInitInfoImpl)info).getORB ();
configure( orb.getConfiguration());
}
public void configure(Configuration configuration)
throws ConfigurationException
{
logger =
configuration.getLogger("org.jacorb.security.sas.TSS.log.verbosity");
useSsl =
configuration.getAttribute("jacorb.security.sas.tss.requires_sas","false").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 (IllegalArgumentException e)
{
logger.error ("Caught ", e);
throw new ConfigurationException ("Could not load SAS context class " + contextClass);
}
catch (ClassNotFoundException e)
{
logger.error ("Caught ", e);
throw new ConfigurationException ("Could not load SAS context class " + contextClass);
}
catch (InstantiationException e)
{
logger.error ("Caught ", e);
throw new ConfigurationException ("Could not load SAS context class " + contextClass);
}
catch (IllegalAccessException e)
{
logger.error ("Caught ", e);
throw new ConfigurationException ("Could not load SAS context class " + contextClass);
}
sasContext.configure(configuration);
sasContext.initTarget();
}
public String name()
{
return name;
}
public void destroy()
{
}
public void receive_request_service_contexts( ServerRequestInfo sri )
throws ForwardRequest
{
ServerRequestInfoImpl ri = ((ServerRequestInfoImpl)sri);
if (logger.isDebugEnabled())
logger.debug("receive_request_service_contexts for " + ri.operation());
// First check whether the target is interested in SAS at all
Policy targetSasPolicy = null;
try {
targetSasPolicy = ri.get_server_policy(SAS_POLICY_TYPE.value);
}
catch(Exception ex) {
}
if( targetSasPolicy == null ) {
// No such policy exist on the target object so there is no point in attempting to call the validateContext
// since the target didn't ask for it
return;
}
if (sasContext == null || ri.isLocalInterceptor())
{
return;
}
GIOPConnection connection = ri.getConnection();
// verify SSL requirements
if (useSsl && !connection.isSSL())
{
if (logger.isErrorEnabled())
logger.error("SSL required for operation " + ri.operation());
throw new org.omg.CORBA.NO_PERMISSION("SSL Required!",
MinorCodes.SAS_TSS_FAILURE,
CompletionStatus.COMPLETED_NO);
}
// parse service context
SASContextBody contextBody = null;
long client_context_id = 0;
byte[] contextToken = null;
try
{
ServiceContext ctx =
ri.get_request_service_context(SASInitializer.SecurityAttributeService);
Any ctx_any =
codec.decode_value( ctx.context_data, SASContextBodyHelper.type() );
contextBody = SASContextBodyHelper.extract(ctx_any);
}
catch (BAD_PARAM e)
{
}
catch (Exception e)
{
if (logger.isWarnEnabled())
logger.warn("Could not parse service context: ", e);
makeContextError(ri, client_context_id, 1, 1, new byte[0]);
throw new org.omg.CORBA.NO_PERMISSION("Could not parse service context: " +
e,
MinorCodes.SAS_TSS_FAILURE,
CompletionStatus.COMPLETED_NO);
}
if (contextBody == null)
return;
// process MessageInContext
if (contextBody.discriminator() == MTMessageInContext.value)
{
MessageInContext msg = null;
try
{
msg = contextBody.in_context_msg();
client_context_id = msg.client_context_id;
contextToken = getSASContext(connection, msg.client_context_id);
}
catch (Exception e)
{
if (logger.isErrorEnabled())
logger.error("Could not parse service MessageInContext " +
ri.operation() + ": " + e);
makeContextError(ri, client_context_id, 1, 1, new byte[0]);
throw new org.omg.CORBA.NO_PERMISSION("SAS Error parsing MessageInContext: " +
e,
MinorCodes.SAS_TSS_FAILURE,
CompletionStatus.COMPLETED_NO);
}
if (contextToken == null)
{
if (logger.isErrorEnabled())
logger.error("Invalid context in MessageInContext " +
ri.operation() + ": " + msg.client_context_id);
makeContextError(ri, client_context_id, 2, 1, new byte[0]);
throw new org.omg.CORBA.NO_PERMISSION("SAS Invalid context in MessageInContext",
MinorCodes.SAS_TSS_FAILURE,
CompletionStatus.COMPLETED_NO);
}
}
// process EstablishContext
String principalName = null;
if (contextBody.discriminator() == MTEstablishContext.value)
{
EstablishContext msg = null;
try
{
msg = contextBody.establish_msg();
client_context_id = msg.client_context_id;
contextToken = msg.client_authentication_token;
if (!sasContext.validateContext(orb, codec, contextToken)) {
logger.info("Could not validate context EstablishContext " + ri.operation());
makeContextError(ri, client_context_id, 1, 1, contextToken);
throw new org.omg.CORBA.NO_PERMISSION("SAS Error validating context",
MinorCodes.SAS_TSS_FAILURE,
CompletionStatus.COMPLETED_NO);
}
principalName = sasContext.getValidatedPrincipal();
}
catch (org.omg.CORBA.NO_PERMISSION e)
{
if (logger.isErrorEnabled())
logger.error("Err " + ri.operation() + ": " + e);
makeContextError(ri, client_context_id, 1, 1, contextToken);
throw e;
}
catch (Exception e)
{
if (logger.isErrorEnabled())
logger.error("Could not parse service EstablishContext " +
ri.operation() + ": " + e);
makeContextError(ri, client_context_id, 1, 1, contextToken);
throw new org.omg.CORBA.NO_PERMISSION("SAS Error parsing EstablishContext: " +
e, MinorCodes.SAS_TSS_FAILURE,
CompletionStatus.COMPLETED_NO);
}
if (contextToken == null)
{
if (logger.isErrorEnabled())
logger.error("Could not parse service EstablishContext " +
ri.operation() + ": " + msg.client_context_id);
makeContextError(ri, client_context_id, 1, 1, contextToken);
throw new org.omg.CORBA.NO_PERMISSION("SAS Error parsing EstablishContext",
MinorCodes.SAS_TSS_FAILURE,
CompletionStatus.COMPLETED_NO);
}
}
// set slots
try
{
Any nameAny = orb.create_any();
if (principalName == null)
principalName =
getSASContextPrincipalName(connection, client_context_id);
nameAny.insert_string(principalName);
ri.set_slot( SASInitializer.sasPrincipalNamePIC, nameAny);
}
catch (Exception e)
{
if (logger.isErrorEnabled())
logger.error("Error inserting service context into slots for " +
ri.operation() + ": " + e);
makeContextError(ri, client_context_id, 1, 1, contextToken);
throw new org.omg.CORBA.NO_PERMISSION("SAS Error insert service context into slots: " + e,
MinorCodes.SAS_TSS_FAILURE,
CompletionStatus.COMPLETED_NO);
}
}
public void receive_request( ServerRequestInfo sri )
throws ForwardRequest
{
ServerRequestInfoImpl ri = ((ServerRequestInfoImpl)sri);
if (logger.isDebugEnabled())
logger.debug("receive_request for "+ri.operation());
if (sasContext == null || ri.isLocalInterceptor())
{
return;
}
GIOPConnection connection = ri.getConnection();
// check policy
SASPolicyValues sasValues = null;
try
{
ObjectImpl oi =
(ObjectImpl)ri.target();
org.jacorb.orb.Delegate d =
(org.jacorb.orb.Delegate)oi._get_delegate();
SASPolicy policy =
(SASPolicy)d.getPOA().getPolicy(SAS_POLICY_TYPE.value);
if (policy != null)
sasValues = policy.value();
}
catch (BAD_PARAM e)
{
if (logger.isDebugEnabled())
logger.debug("No SAS Policy for "+ri.operation());
}
catch (Exception e)
{
if (logger.isWarnEnabled())
logger.warn("Error fetching SAS policy for "+
ri.operation()+": "+e);
throw new org.omg.CORBA.NO_PERMISSION("Error fetching SAS policy: "+e,
MinorCodes.SAS_TSS_FAILURE,
CompletionStatus.COMPLETED_NO);
}
if (sasValues == null)
return;
if (sasValues.targetRequires == 0 && sasValues.targetSupports == 0)
return;
ATLASPolicyValues atlasValues = null;
try
{
ObjectImpl oi = (ObjectImpl)ri.target();
org.jacorb.orb.Delegate d = (org.jacorb.orb.Delegate)oi._get_delegate();
ATLASPolicy policy = (ATLASPolicy)d.getPOA().getPolicy(ATLAS_POLICY_TYPE.value);
if (policy != null)
atlasValues = policy.value();
}
catch (BAD_PARAM e)
{
if (logger.isDebugEnabled())
logger.debug("No ATLAS Policy for "+ri.operation());
}
catch (Exception e)
{
if (logger.isWarnEnabled())
logger.warn("Error fetching ATLAS policy for "+
ri.operation()+": "+e);
throw new org.omg.CORBA.NO_PERMISSION("Error fetching ATLAS policy: "+e,
MinorCodes.SAS_TSS_FAILURE,
CompletionStatus.COMPLETED_NO);
}
// parse service context
SASContextBody contextBody = null;
long client_context_id = 0;
byte[] contextToken = null;
try
{
ServiceContext ctx =
ri.get_request_service_context(SASInitializer.SecurityAttributeService);
Any ctx_any =
codec.decode_value( ctx.context_data, SASContextBodyHelper.type() );
contextBody =
SASContextBodyHelper.extract(ctx_any);
}
catch (BAD_PARAM e)
{
if (logger.isDebugEnabled())
logger.debug("Could not parse service context for operation " +
ri.operation());
}
catch (Exception e)
{
if (logger.isWarnEnabled())
logger.warn("Could not parse service context for operation " +
ri.operation() + ": " + e);
}
if (contextBody == null &&
(sasValues.targetRequires & org.omg.CSIIOP.EstablishTrustInClient.value) != 0 &&
!ri.operation().equals("_non_existent") &&
!ri.operation().equals("_is_a"))
{
if (logger.isErrorEnabled())
logger.error("Did not parse service context for operation " +
ri.operation());
throw new org.omg.CORBA.NO_PERMISSION("No SAS service context found",
MinorCodes.SAS_TSS_FAILURE,
CompletionStatus.COMPLETED_NO);
}
if (contextBody == null)
{
if (logger.isDebugEnabled())
logger.debug("No context found, but not required");
return;
}
// process MessageInContext
if (contextBody.discriminator() == MTMessageInContext.value)
{
MessageInContext msg = null;
try
{
msg = contextBody.in_context_msg();
client_context_id = msg.client_context_id;
contextToken = getSASContext(connection, msg.client_context_id);
}
catch (Exception e)
{
if (logger.isErrorEnabled())
logger.error("Could not parse service MessageInContext " +
ri.operation() + ": " + e);
makeContextError(ri, client_context_id, 1, 1, contextToken);
throw new org.omg.CORBA.NO_PERMISSION("SAS Error parsing MessageInContext: " + e,
MinorCodes.SAS_TSS_FAILURE,
CompletionStatus.COMPLETED_NO);
}
if (contextToken == null)
{
if (logger.isErrorEnabled())
logger.error("Could not find context in MessageInContext " +
ri.operation() + ": " + msg.client_context_id);
makeContextError(ri, client_context_id, 2, 1, contextToken);
throw new org.omg.CORBA.NO_PERMISSION("SAS Error invalid context in MessageInContext",
MinorCodes.SAS_TSS_FAILURE,
CompletionStatus.COMPLETED_NO);
}
}
// process EstablishContext
if (contextBody.discriminator() == MTEstablishContext.value)
{
EstablishContext msg = null;
String principalName = null;
try
{
msg = contextBody.establish_msg();
client_context_id = msg.client_context_id;
contextToken = msg.client_authentication_token;
principalName = sasContext.getValidatedPrincipal();
}
catch (org.omg.CORBA.NO_PERMISSION e)
{
if (logger.isErrorEnabled())
logger.error("Err " + ri.operation() + ": " + e);
makeContextError(ri, client_context_id, 1, 1, contextToken);
throw e;
}
catch (Exception e)
{
if (logger.isErrorEnabled())
logger.error("Could not parse service EstablishContext " +
ri.operation() + ": " + e);
makeContextError(ri, client_context_id, 2, 1, contextToken);
throw new org.omg.CORBA.NO_PERMISSION("SAS Error parsing EstablishContext: " + e,
MinorCodes.SAS_TSS_FAILURE,
CompletionStatus.COMPLETED_NO);
}
if (contextToken == null)
{
if (logger.isErrorEnabled())
logger.error("Could not parse service EstablishContext " +
ri.operation() + ": " + msg.client_context_id);
makeContextError(ri, client_context_id, 2, 1, contextToken);
throw new org.omg.CORBA.NO_PERMISSION("SAS Error parsing EstablishContext",
MinorCodes.SAS_TSS_FAILURE,
CompletionStatus.COMPLETED_NO);
}
// cache context
if (sasValues.stateful)
cacheSASContext(connection, msg.client_context_id,
contextToken, principalName);
}
// set slots
try
{
makeCompleteEstablishContext(ri, client_context_id, sasValues);
}
catch (Exception e)
{
if (logger.isErrorEnabled())
logger.error("Error inserting service context into slots for " +
ri.operation() + ": " + e);
makeContextError(ri, client_context_id, 1, 1, contextToken);
throw new org.omg.CORBA.NO_PERMISSION("SAS Error insert service context into slots: " + e, MinorCodes.SAS_TSS_FAILURE, CompletionStatus.COMPLETED_NO);
}
}
public void send_reply( ServerRequestInfo ri )
{
if (logger.isDebugEnabled())
logger.debug("send_reply for "+ri.operation());
/*
Any slot_any = null;
try
{
slot_any = ri.get_slot(sasReplySlotID);
}
catch (BAD_PARAM e)
{
if (logger.isDebugEnabled())
logger.debug("No SAS reply found " + ri.operation() + ": ");
}
catch (Exception e)
{
if (logger.isWarnEnabled())
logger.warn("No SAS reply found " + ri.operation() + ": ");
}
if (slot_any == null) return;
try
{
ri.add_reply_service_context(
new ServiceContext(SASInitializer.SecurityAttributeService,
codec.encode_value( slot_any ) ),
true);
}
catch (Exception e)
{
if (logger.isErrorEnabled())
logger.error("Error setting reply service context " +
ri.operation() + ": " + e);
throw new org.omg.CORBA.NO_PERMISSION("SAS Error setting reply service contex: " + e,
MinorCodes.SAS_TSS_FAILURE,
CompletionStatus.COMPLETED_MAYBE);
}
*/
}
public void send_exception( ServerRequestInfo ri )
throws ForwardRequest
{
if (logger.isDebugEnabled())
logger.debug("send_exception for "+ri.operation());
/*
//if (!useSAS) return;
Any slot_any = null;
try
{
slot_any = ri.get_slot(sasReplySlotID);
}
catch (BAD_PARAM e)
{
if (logger.isDebugEnabled())
logger.debug("No SAS reply found " + ri.operation() + ": ");
}
catch (Exception e)
{
if (logger.isWarnEnabled())
logger.warn("No SAS reply found " + ri.operation() + ": ");
}
if (slot_any == null)
return;
try
{
ri.add_reply_service_context(
new ServiceContext(
SASInitializer.SecurityAttributeService,
codec.encode_value( slot_any )
),
true);
}
catch (Exception e)
{
if (logger.isErrorEnabled())
logger.error("Error setting reply service context:" + e);
throw new org.omg.CORBA.NO_PERMISSION("SAS Error setting reply service context: " + e,
MinorCodes.SAS_TSS_FAILURE,
CompletionStatus.COMPLETED_MAYBE);
}
*/
}
public void send_other( ServerRequestInfo ri )
throws ForwardRequest
{
if (logger.isDebugEnabled())
logger.debug("send_other for "+ri.operation());
}
protected Any makeCompleteEstablishContext(ServerRequestInfo ri, long client_context_id, SASPolicyValues sasValues) {
CompleteEstablishContext msg = new CompleteEstablishContext();
msg.client_context_id = client_context_id;
msg.context_stateful = sasValues.stateful;
msg.final_context_token = new byte[0];
SASContextBody contextBody = new SASContextBody();
contextBody.complete_msg(msg);
Any any = orb.create_any();
SASContextBodyHelper.insert( any, contextBody );
if (ri != null)
{
try
{
ri.add_reply_service_context(new ServiceContext(SASInitializer.SecurityAttributeService, codec.encode_value( any ) ), true);
}
catch (Exception e)
{
logger.error("Error setting reply service context:" + e);
throw new org.omg.CORBA.NO_PERMISSION("SAS Error setting reply service context: " + e, MinorCodes.SAS_TSS_FAILURE, CompletionStatus.COMPLETED_MAYBE);
}
}
return any;
}
protected Any makeContextError(ServerRequestInfo ri, long client_context_id, int major_status, int minor_status, byte[] error_token) {
ContextError msg = new ContextError();
msg.client_context_id = client_context_id;
msg.error_token = error_token;
msg.major_status = major_status;
msg.minor_status = minor_status;
SASContextBody contextBody = new SASContextBody();
contextBody.error_msg(msg);
Any any = orb.create_any();
SASContextBodyHelper.insert( any, contextBody );
if (ri != null)
{
try
{
ri.add_reply_service_context(new ServiceContext(SASInitializer.SecurityAttributeService, codec.encode_value( any ) ), true);
}
catch (Exception e)
{
logger.error("Error setting reply service context:" + e);
throw new org.omg.CORBA.NO_PERMISSION("SAS Error setting reply service context: " + e, MinorCodes.SAS_TSS_FAILURE, CompletionStatus.COMPLETED_MAYBE);
}
}
return any;
}
// manage cached contexts
class CachedContext
{
public byte[] client_authentication_token;
public String principalName;
CachedContext(byte[] client_authentication_token, String principalName)
{
this.client_authentication_token = client_authentication_token;
this.principalName = principalName;
}
}
public void cacheSASContext(GIOPConnection connection,
long client_context_id,
byte[] client_authentication_token,
String principalName)
{
synchronized ( connection )
{
Hashtable sasContexts =
(Hashtable) connection.get_cubby(sasContextsCubby);
if (sasContexts == null)
{
sasContexts = new Hashtable();
connection.set_cubby(sasContextsCubby, sasContexts);
}
sasContexts.put(new Long(client_context_id),
new CachedContext(client_authentication_token, principalName));
}
}
public void purgeSASContext(GIOPConnection connection, long client_context_id)
{
synchronized ( connection )
{
Hashtable sasContexts = (Hashtable) connection.get_cubby(sasContextsCubby);
if (sasContexts == null)
{
sasContexts = new Hashtable();
connection.set_cubby(sasContextsCubby, sasContexts);
}
sasContexts.remove(new Long(client_context_id));
}
}
public byte[] getSASContext(GIOPConnection connection, long client_context_id)
{
Long key = new Long(client_context_id);
synchronized ( connection )
{
Hashtable sasContexts = (Hashtable) connection.get_cubby(sasContextsCubby);
if (sasContexts == null)
{
sasContexts = new Hashtable();
connection.set_cubby(sasContextsCubby, sasContexts);
}
if (!sasContexts.containsKey(key))
return null;
return ((CachedContext)sasContexts.get(key)).client_authentication_token;
}
}
public String getSASContextPrincipalName(GIOPConnection connection,
long client_context_id)
{
Long key = new Long(client_context_id);
synchronized ( connection )
{
Hashtable sasContexts =
(Hashtable) connection.get_cubby(sasContextsCubby);
if (sasContexts == null)
{
sasContexts = new Hashtable();
connection.set_cubby(sasContextsCubby, sasContexts);
}
if (!sasContexts.containsKey(key))
return null;
return ((CachedContext)sasContexts.get(key)).principalName;
}
}
}