From 781d35d7fb08201a8a23b0756c69bf00c0e3ee67 Mon Sep 17 00:00:00 2001 From: Chris Cleeland Date: Tue, 3 Apr 2007 19:37:44 +0000 Subject: Committing changes thus far in preparation to migrate them to the new oci_mixed_security_2 branch. --- .../SSLIOP/SSLIOP_Invocation_Interceptor.cpp | 285 +++++++++++++++++++-- .../orbsvcs/SSLIOP/SSLIOP_Invocation_Interceptor.h | 22 +- .../orbsvcs/SSLIOP/SSLIOP_ORBInitializer.cpp | 32 +-- .../orbsvcs/Security/SL2_SecurityManager.cpp | 259 +++++++++++++++++++ TAO/orbsvcs/orbsvcs/Security/SL2_SecurityManager.h | 206 +++++++++++++++ .../orbsvcs/Security/Security_ORBInitializer.cpp | 74 ++++-- TAO/orbsvcs/orbsvcs/SecurityLevel2.idl | 19 ++ 7 files changed, 822 insertions(+), 75 deletions(-) create mode 100644 TAO/orbsvcs/orbsvcs/Security/SL2_SecurityManager.cpp create mode 100644 TAO/orbsvcs/orbsvcs/Security/SL2_SecurityManager.h diff --git a/TAO/orbsvcs/orbsvcs/SSLIOP/SSLIOP_Invocation_Interceptor.cpp b/TAO/orbsvcs/orbsvcs/SSLIOP/SSLIOP_Invocation_Interceptor.cpp index 5ce2d53c82c..57bedb1ed32 100644 --- a/TAO/orbsvcs/orbsvcs/SSLIOP/SSLIOP_Invocation_Interceptor.cpp +++ b/TAO/orbsvcs/orbsvcs/SSLIOP/SSLIOP_Invocation_Interceptor.cpp @@ -1,9 +1,11 @@ #include "orbsvcs/SSLIOP/SSLIOP_Invocation_Interceptor.h" +#include "orbsvcs/SSLIOP/SSLIOP_Current.h" #include "orbsvcs/SecurityLevel2C.h" #include "tao/ORB_Constants.h" #include "tao/PortableServer/PS_CurrentC.h" +#include "tao/PortableServer/POAC.h" #include "tao/debug.h" #if defined(SSLIOP_DEBUG_PEER_CERTIFICATE) @@ -17,12 +19,49 @@ ACE_RCSID (SSLIOP, TAO_BEGIN_VERSIONED_NAMESPACE_DECL -TAO::SSLIOP::Server_Invocation_Interceptor::Server_Invocation_Interceptor ( - ::SSLIOP::Current_ptr current, - ::Security::QOP qop) - : ssliop_current_ (::SSLIOP::Current::_duplicate (current)), - qop_ (qop) +TAO::SSLIOP::Server_Invocation_Interceptor::Server_Invocation_Interceptor +( + PortableInterceptor::ORBInitInfo_ptr info, + ::Security::QOP default_qop, + size_t tss_slot +) +: qop_ (default_qop) { + /* + * Cache references to the "Current" objects that we'll need during + * during invocations. + */ + + CORBA::Object_var obj = + info->resolve_initial_references ("SSLIOPCurrent"); + + this->ssliop_current_ = ::SSLIOP::Current::_narrow (obj.in ()); + + if (!CORBA::is_nil (this->ssliop_current_.in ())) + { + TAO::SSLIOP::Current *tao_current = + dynamic_cast (this->ssliop_current_.in ()); + + if (tao_current != 0) + { + if (TAO_debug_level > 3) + ACE_DEBUG ((LM_DEBUG, "TAO (%P|%t) SSLIOP_Invocation_Interceptor::CTOR--setting up SSLIOP Current with slot %d\n", tss_slot)); + tao_current->tss_slot (tss_slot); + } + else + throw CORBA::INTERNAL (); + } + + obj = info->resolve_initial_references ("SecurityLevel2:SecurityManager"); + this->sec2manager_ = SecurityLevel2::SecurityManager::_narrow (obj.in ()); + + if (! CORBA::is_nil (this->sec2manager_.in ())) + { + // set the slot id? + } + + obj = info->resolve_initial_references ("POACurrent"); + this->poa_current_ = PortableServer::Current::_narrow (obj.in ()); } TAO::SSLIOP::Server_Invocation_Interceptor::~Server_Invocation_Interceptor ( @@ -30,6 +69,7 @@ TAO::SSLIOP::Server_Invocation_Interceptor::~Server_Invocation_Interceptor ( { } + char * TAO::SSLIOP::Server_Invocation_Interceptor::name () ACE_THROW_SPEC ((CORBA::SystemException)) @@ -46,10 +86,43 @@ TAO::SSLIOP::Server_Invocation_Interceptor::destroy () void TAO::SSLIOP::Server_Invocation_Interceptor::receive_request_service_contexts ( - PortableInterceptor::ServerRequestInfo_ptr /*ri*/) + PortableInterceptor::ServerRequestInfo_ptr /* ri */) + ACE_THROW_SPEC ((CORBA::SystemException, + PortableInterceptor::ForwardRequest)) +{ +#if 1 + // This operation is where the old security implementation used to + // makes its simplistic decision whether to permit or deny, but with + // the introduction of more detailed checking, there's a need to + // have access to information that's not available until later in + // the PI flow. So, it's now all moved into receive_request(). + + + CORBA::Boolean const no_ssl = + this->ssliop_current_->no_context (); + + if (TAO_debug_level >= 3) + ACE_DEBUG ((LM_DEBUG, "SSLIOP (%P|%t) Interceptor (context), ssl=%d\n", !(no_ssl))); + + // if + // (1) no SSL session state is available (which means that the + // invocation is received across a non-SSL transport) + // AND + // (2) the required Quality of Protection is something other + // than SecQOPNoProtection (set via -SSLNoProtection) + if (no_ssl && this->qop_ != ::Security::SecQOPNoProtection) + throw CORBA::NO_PERMISSION (); +#endif +} + + +void +TAO::SSLIOP::Server_Invocation_Interceptor::receive_request ( + PortableInterceptor::ServerRequestInfo_ptr ri) ACE_THROW_SPEC ((CORBA::SystemException, PortableInterceptor::ForwardRequest)) { +#if 0 // The current upcall is not being performed through an SSL // connection. If server is configured to disallow insecure // invocations then throw a CORBA::NO_PERMISSION exception. @@ -59,14 +132,192 @@ TAO::SSLIOP::Server_Invocation_Interceptor::receive_request_service_contexts ( // SecTargetSecureInvocationPolicy so that we can // accept or reject requests on a per-object basis // instead on a per-endpoint basis. - CORBA::Boolean const no_ssl = - this->ssliop_current_->no_context (); - if (TAO_debug_level >= 3) - ACE_DEBUG ((LM_DEBUG, "SSLIOP (%P|%t) Interceptor (context), ssl=%d\n", !(no_ssl))); +#if 1 + /* + // Of course, since we're implementing a SecurityManager, we can do + // this now! But we want to keep the default behavior, too... - if (no_ssl && this->qop_ != ::Security::SecQOPNoProtection) - throw CORBA::NO_PERMISSION (); + Q: It's also not clear how we're supposed to query the securitymanager + "for the current object's SecureInvocationPolicy". Maybe we need to + query the policies on the object itself? Maybe we can ask the + ServerRequestInfo via get_server_policy()? + + A: The spec says that "This operation returns the policy in effect + for this operation for the given policy type. The returned + CORBA::Policy object shall only be a policy whose type was + registered via register_policy_factory()", so that should give us + what we want. + */ + + SecurityLevel2::AccessDecision_var ad = + this->sec2manager_->access_decision (); + + + CORBA::Boolean const no_ssl = + this->ssliop_current_->no_context (); + + if (TAO_debug_level >= 3) + ACE_DEBUG ((LM_DEBUG, "SSLIOP (%P|%t) Interceptor (context), ssl=%d\n", !(no_ssl))); + + // if + // (1) no SSL session state is available (which means that the + // invocation is received across a non-SSL transport) + // AND + // (2) the required Quality of Protection is something other + // than SecQOPNoProtection (set via -SSLNoProtection) + if (no_ssl && this->qop_ != ::Security::SecQOPNoProtection) +#if 0 + throw CORBA::NO_PERMISSION (); + if ( ! CORBA:is_nil (ad.in ()) + && ri->get_server_policy(SecureInvocationPolicy) == SecTargetSecureInvocationPolicy) +#endif + { + /* + * Set up all the arguments needed by the call + * to AccessDecision::access_allowed() + */ + + /* Get the credentials from SSLIOP */ + SecurityLevel2::CredentialsList cred_list; // initial empty? +#if 0 + try { + SecurityLevel2::ReceivedCredentials_var rcvd_creds = + this->sec2_current_->received_credentials (); + // this gets the credentials received from the other side. We + // should be able to put this into a CredentialsList with no + // problem. + // + // Do I really need to implement a sec2_current, or can I hack + // the conversion at this level? I probably ought to do it as + // a real sec2_current with the conversion from sec3->sec2 + // happening at a lower level. + + cred_list.length(1); + cred_list[0] = rcvd_creds.in (); + /* + So, in looking for how we can do this, I find that the + SL3_SecurityCurrent::client_credentials() delegates to SL3_SecurityCurrent_Impl::client_credentials(), which is pure virtual. + */ + } + catch (...) { + } +#endif + + /* Get the target object */ + CORBA::Object_var target = CORBA::Object::_nil (); + +#if 0 // we want to use the POACurrent::get_reference()! + // I suppose that we can derive this using server_id, adapter_id + // and object_id using id_to_reference. One problem is that, + // according to the spec, id_to_reference() can only be used + // when the POA in question has the RETAIN policy so this would + // be unavailable when the POA has NO_RETAIN. + try { + int no_args = 0; + CORBA::ORB_var orb = CORBA::ORB_init (no_args, 0, ri->orb_id()); + CORBA::Object_var obj = orb->resolve_initial_references ("RootPOA"); + PortableServer::POA_var rootpoa = + PortableServer::POA::_narrow (obj.in ()); + if (CORBA::is_nil (rootpoa.in ())) + // Probably not a good choice for exception, but we need to + // throw something. + throw PortableServer::POA::AdapterNonExistent(); + + // @@CJC Grrr...of course nothing is ever easy. What we'd really + // like to be able to do is something like... + // rootpoa->find_POA (ri->adapter_id (), false); // don't activate + // to get a reference to the POA indicated here. Sigh. CORBA 3.0 + // provides adapter_name(), so maybe I'll get lucky and that'll be + // available. Otherwise, I'm going to have to resort to ugliness + // and proprietary hacks to get this info, b/c adapter_id() + // returns an opaque octet sequence. + // + // The good news is that adapter_name() exists, but it doesn't + // return a name suitable for submission to find_POA(). Rather, + // it returns a string sequence. Exactly what's in that sequence + // we don't know, but I'll guess that it's supposed to be an in-order + // list of the poa path down to the poa that's hosting the target + // CORBA Object. So, if we look at the last element in the sequence + // we should get the name of the hosting POA. + PortableInterceptor::AdapterName_var poa_path = ri->adapter_name (); + size_t last_component_index = poa_path->length() - 1; + + const char* last_component = poa_path[last_component_index]; + PortableServer::POA_var poa = + rootpoa->find_POA (last_component, + false); // don't activate + + // Yow. Sometimes the C++ mapping mystifies me in its oddities. + // One would expect that, since the requestinfo has an ObjectId + // attribute, and the id_to_reference() operation takes an ObjectId + // as an "in" argument, that one could simply do + // target = poa->id_to_reference (ri->object_id()) + // Alas, 'tis not that simple. The mapping for a return value for + // an unbounded sequence is T*, and the mapping for an "in" is + // const T&, which means that we have to dereference the pointer. + // + // Damn, that's really ugly. But I'm glad that's off my chest. + target = poa->id_to_reference (*(ri->object_id ())); + } +#define quote(x) #x + catch (const PortableServer::POA::ObjectNotActive& e) { + // thrown by id_to_reference() + e._tao_print_exception ("ssliop_invocation_interceptor::receive_request @ " quote(__LINE__)); + } + catch (const PortableServer::POA::WrongPolicy& e) { + // thrown by id_to_reference() + e._tao_print_exception ("ssliop_invocation_interceptor::receive_request @ " quote(__LINE__)); + } + catch (const PortableServer::POA::AdapterNonExistent& e) { + // thrown by find_POA() + e._tao_print_exception ("yoyoyo ssliop_invocation_interceptor::receive_request @ " quote(__LINE__)); + } + catch (const CORBA::ORB::InvalidName& e) { + // thrown by resolve_initial_references() + e._tao_print_exception ("ssliop_invocation_interceptor::receive_request @ " quote(__LINE__)); + } +#else + target = this->poa_current_->get_reference (); +#endif + + char* operation_name = ri->operation (); + char* target_interface_name = ri->target_most_derived_interface(); // is this the repository ID? + + CORBA::Boolean it_should_happen = false; + if (ad) + it_should_happen = ad->access_allowed (cred_list, + target.in(), + operation_name, + target_interface_name); + else + it_should_happen = true; // if no access_decision, then let it all through + + if (! it_should_happen) + { + throw CORBA::NO_PERMISSION (); + } + } + else +#endif + { + // PREVIOUS DEFAULT BEHAVIOR + + CORBA::Boolean const no_ssl = + this->ssliop_current_->no_context (); + + if (TAO_debug_level >= 3) + ACE_DEBUG ((LM_DEBUG, "SSLIOP (%P|%t) Interceptor (context), ssl=%d\n", !(no_ssl))); + + // if + // (1) no SSL session state is available (which means that the + // invocation is received across a non-SSL transport) + // AND + // (2) the required Quality of Protection is something other + // than SecQOPNoProtection (set via -SSLNoProtection) + if (no_ssl && this->qop_ != ::Security::SecQOPNoProtection) + throw CORBA::NO_PERMISSION (); + } #if defined(DEBUG_PEER_CERTIFICATES) try @@ -126,15 +377,7 @@ TAO::SSLIOP::Server_Invocation_Interceptor::receive_request_service_contexts ( throw CORBA::NO_PERMISSION (); } #endif /* DEBUG_PEER_CERTIFICATES */ -} - - -void -TAO::SSLIOP::Server_Invocation_Interceptor::receive_request ( - PortableInterceptor::ServerRequestInfo_ptr /* ri */) - ACE_THROW_SPEC ((CORBA::SystemException, - PortableInterceptor::ForwardRequest)) -{ +#endif } void diff --git a/TAO/orbsvcs/orbsvcs/SSLIOP/SSLIOP_Invocation_Interceptor.h b/TAO/orbsvcs/orbsvcs/SSLIOP/SSLIOP_Invocation_Interceptor.h index e382a2042a2..2ae6d0bc9a7 100644 --- a/TAO/orbsvcs/orbsvcs/SSLIOP/SSLIOP_Invocation_Interceptor.h +++ b/TAO/orbsvcs/orbsvcs/SSLIOP/SSLIOP_Invocation_Interceptor.h @@ -22,8 +22,11 @@ #endif /* ACE_LACKS_PRAGMA_ONCE */ #include "orbsvcs/SSLIOPC.h" +#include "orbsvcs/SecurityLevel2C.h" #include "tao/PortableInterceptorC.h" +#include "tao/PI/ORBInitInfo.h" #include "tao/PI_Server/PI_Server.h" +#include "tao/PortableServer/PS_CurrentC.h" #include "tao/LocalObject.h" // This is to remove "inherits via dominance" warnings from MSVC. @@ -55,9 +58,16 @@ namespace TAO { public: - /// Constructor. - Server_Invocation_Interceptor (::SSLIOP::Current_ptr current, - ::Security::QOP qop); + /*! + \brief Constructor. + \param info reference to the ORBInitInfo object so that + the interceptor can get access to initial references, etc. + \param default_qop the default Quality of Protection + \param tss_slot the TSS slot used by the various security features. + */ + Server_Invocation_Interceptor (PortableInterceptor::ORBInitInfo_ptr info, + ::Security::QOP default_qop, + size_t tss_slot); /** * @name PortableInterceptor::ServerRequestInterceptor Methods @@ -124,9 +134,15 @@ namespace TAO /// Reference to the current SSLIOP execution context. ::SSLIOP::Current_var ssliop_current_; + /// Reference to the POA current + PortableServer::Current_var poa_current_; + /// The default quality-of-protection settings in use. ::Security::QOP qop_; + /// SecurityLevel2 security manager reference + SecurityLevel2::SecurityManager_var sec2manager_; + SecurityLevel2::Current_var sec2_current_; }; } // End SSLIOP namespace. diff --git a/TAO/orbsvcs/orbsvcs/SSLIOP/SSLIOP_ORBInitializer.cpp b/TAO/orbsvcs/orbsvcs/SSLIOP/SSLIOP_ORBInitializer.cpp index 102fbeb2246..faccc92f0f1 100644 --- a/TAO/orbsvcs/orbsvcs/SSLIOP/SSLIOP_ORBInitializer.cpp +++ b/TAO/orbsvcs/orbsvcs/SSLIOP/SSLIOP_ORBInitializer.cpp @@ -88,35 +88,14 @@ TAO::SSLIOP::ORBInitializer::post_init ( // object is registered for each ORB in this ORBInitializer's // pre_init() method. - CORBA::Object_var obj = - info->resolve_initial_references ("SSLIOPCurrent"); - - SSLIOP::Current_var ssliop_current = - SSLIOP::Current::_narrow (obj.in ()); - - if (!CORBA::is_nil (ssliop_current.in ())) - { - TAO::SSLIOP::Current *tao_current = - dynamic_cast (ssliop_current.in ()); - - if (tao_current != 0) - { - const size_t slot = - this->get_tss_slot_id (info); - - tao_current->tss_slot (slot); - } - else - throw CORBA::INTERNAL (); - } - // Create the SSLIOP secure invocation server request interceptor. PortableInterceptor::ServerRequestInterceptor_ptr si = PortableInterceptor::ServerRequestInterceptor::_nil (); ACE_NEW_THROW_EX (si, - TAO::SSLIOP::Server_Invocation_Interceptor ( - ssliop_current.in (), - this->qop_), + TAO::SSLIOP::Server_Invocation_Interceptor + (info, + this->qop_, + this->get_tss_slot_id (info)), CORBA::NO_MEMORY ( CORBA::SystemException::_tao_minor_code ( TAO::VMCID, @@ -161,7 +140,8 @@ TAO::SSLIOP::ORBInitializer::post_init ( // Register the SSLIOP-specific vault with the // PrincipalAuthenticator. - obj = info->resolve_initial_references ("SecurityLevel3:SecurityManager"); + CORBA::Object_var obj = + info->resolve_initial_references ("SecurityLevel3:SecurityManager"); SecurityLevel3::SecurityManager_var manager = SecurityLevel3::SecurityManager::_narrow (obj.in ()); diff --git a/TAO/orbsvcs/orbsvcs/Security/SL2_SecurityManager.cpp b/TAO/orbsvcs/orbsvcs/Security/SL2_SecurityManager.cpp new file mode 100644 index 00000000000..bdef351d9cd --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Security/SL2_SecurityManager.cpp @@ -0,0 +1,259 @@ +// $Id$ + +#include "orbsvcs/Security/SL2_SecurityManager.h" + +#include "tao/ORB_Constants.h" + +ACE_RCSID (Security, + SL2_SecurityManager, + "$Id$") + + +TAO_BEGIN_VERSIONED_NAMESPACE_DECL + +TAO::Security::SecurityManager::SecurityManager (/* unknown */) + : principal_authenticator_ (SecurityLevel2::PrincipalAuthenticator::_nil ()) +{ + // this needs to change to access decision + SecurityLevel2::AccessDecision_ptr ad; + ACE_NEW_THROW_EX (ad, + TAO::Security::AccessDecision, + CORBA::NO_MEMORY ( + CORBA::SystemException::_tao_minor_code ( + TAO::VMCID, + ENOMEM), + CORBA::COMPLETED_NO)); + + this->access_decision_ = ad; +} + +TAO::Security::SecurityManager::~SecurityManager (void) +{ +} + +Security::MechandOptionsList* +TAO::Security::SecurityManager::supported_mechanisms () + ACE_THROW_SPEC ((CORBA::SystemException)) +{ + throw CORBA::NO_IMPLEMENT (); +} + +SecurityLevel2::CredentialsList* +TAO::Security::SecurityManager::own_credentials () + ACE_THROW_SPEC ((CORBA::SystemException)) +{ + throw CORBA::NO_IMPLEMENT (); +} + +SecurityLevel2::RequiredRights_ptr +TAO::Security::SecurityManager::required_rights_object () + ACE_THROW_SPEC ((CORBA::SystemException)) +{ + throw CORBA::NO_IMPLEMENT (); +} + +SecurityLevel2::PrincipalAuthenticator_ptr +TAO::Security::SecurityManager::principal_authenticator () + ACE_THROW_SPEC ((CORBA::SystemException)) +{ + return SecurityLevel2::PrincipalAuthenticator::_duplicate + (this->principal_authenticator_.in () ); +} + +SecurityLevel2::AccessDecision_ptr +TAO::Security::SecurityManager::access_decision () + ACE_THROW_SPEC ((CORBA::SystemException)) +{ + return SecurityLevel2::AccessDecision::_duplicate (this->access_decision_.in () ); +} + +SecurityLevel2::AuditDecision_ptr +TAO::Security::SecurityManager::audit_decision () + ACE_THROW_SPEC ((CORBA::SystemException)) +{ + throw CORBA::NO_IMPLEMENT (); +} + +SecurityLevel2::TargetCredentials_ptr +TAO::Security::SecurityManager::get_target_credentials (CORBA::Object_ptr /*o*/) + ACE_THROW_SPEC ((CORBA::SystemException)) +{ + throw CORBA::NO_IMPLEMENT (); +} + +void +TAO::Security::SecurityManager::remove_own_credentials ( + SecurityLevel2::Credentials_ptr creds) + ACE_THROW_SPEC ((CORBA::SystemException)) +{ + throw CORBA::NO_IMPLEMENT (); +} + +CORBA::Policy_ptr +TAO::Security::SecurityManager::get_security_policy (CORBA::PolicyType policy_type) + ACE_THROW_SPEC ((CORBA::SystemException)) +{ + throw CORBA::NO_IMPLEMENT (); +} + +/* + * AccessDecision stuff below here + */ + +TAO::Security::AccessDecision::AccessDecision () + : default_allowance_decision_ (false) +{ +} + +TAO::Security::AccessDecision::~AccessDecision () +{ +} + +TAO::Security::AccessDecision::OBJECT_KEY +TAO::Security::AccessDecision::map_key_from_objref (CORBA::Object_ptr obj) +{ + // Originally this lived in access_allowed, but it was needed + // in add_object and remove_object, too, so it's been factored out. + // + // We need an ORB reference here. Where do we get it? + // + // The primary place we need this facility is in access_allowed. + // Unfortunately, the interface for access_allowed is cast in + // dormant OMG spec stone, so that can't change. We could pass in a + // reference as an argument to the constructor and store it, but + // what do we do, then, if the same interceptor is registered with + // multiple ORBs (is that possible?!?!)? Then we could end up using + // a different ORB to stringify, which could end up giving us a + // different string, which means they won't compare propertly. + // + // As a hack, we could realize that TAO's CORBA::Object implementation + // has a reference to its associated ORB, and just dip in there + // to get access to it. Ugly, but at least it should probably work. + CORBA::ORB_var orb = obj->_get_orb (); + CORBA::String_var ior = orb->object_to_string (obj); + return ior; +} + +CORBA::Boolean +TAO::Security::AccessDecision::access_allowed ( + const ::SecurityLevel2::CredentialsList & cred_list, + ::CORBA::Object_ptr target, + const char * operation_name, + const char * target_interface_name + ) + ACE_THROW_SPEC ((CORBA::SystemException)) +{ + // @@ I still don't know what we do with the cred_list in here... + // Do we inspect it? + + // Turn the target into what we'll use as a key into the map. + OBJECT_KEY key = this->map_key_from_objref (target); + + // LOCK THE MAP! + ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, guard, this->map_lock_, + this->default_allowance_decision_); + + // Look up the target in access_map_; if there, return the value, + // otherwise return the default value. + CORBA::Boolean access_decision; + if (this->access_map_.find (key, access_decision) == -1) + { + // Couldn't find the IOR in the map, so we use the default + access_decision = this->default_allowance_decision_; + } + + // For now we just return the default. + return access_decision; +} + +void +TAO::Security::AccessDecision::add_object (CORBA::Object_ptr obj, + CORBA::Boolean allow_insecure_access) + ACE_THROW_SPEC ((CORBA::SystemException)) +{ + // make a key from 'obj' + OBJECT_KEY key = this->map_key_from_objref (obj); + + // bind it into the access_map_, replacing anything that's there. + // LOCK THE MAP! + ACE_GUARD (TAO_SYNCH_MUTEX, guard, this->map_lock_); + + // Since we want to replace any existing entry in the map, we just + // use rebind. + errno = 0; // Not sure if this gets set if rebind fails...it only + // appears to fail when an allocation thru the allocator's + // malloc() fails. Depending on the malloc() implementation, + // errno could get set OR an exception thrown. + int ret = this->access_map_.rebind (key, allow_insecure_access); + if (ret == -1) + { + // rebind shouldn't fail under normal circumstances + if (TAO_debug_level > 1) + ACE_DEBUG ((LM_DEBUG, + "TAO (%P|%t): SL2_AccessDecision::add_object(%s,%d) " + "unexpectedly failed (errno=%d)\n", + (const char*)key, + allow_insecure_access, + errno)); + throw + CORBA::NO_MEMORY(CORBA::SystemException::_tao_minor_code (TAO::VMCID, + errno), + CORBA::COMPLETED_NO); + } +} + +void +TAO::Security::AccessDecision::remove_object (CORBA::Object_ptr obj) + ACE_THROW_SPEC ((CORBA::SystemException)) +{ + // make a key from 'obj' + OBJECT_KEY key = this->map_key_from_objref (obj); + + // unbind it from access_map_, no matter if it's not in there... + // LOCK THE MAP! + ACE_GUARD (TAO_SYNCH_MUTEX, guard, this->map_lock_); + + errno = 0; + int ret = this->access_map_.unbind (key); + if (ret == -1) + { + if (errno == ENOENT) + { + // ignore b/c we don't care...maybe log a debug message for info + if (TAO_debug_level >= 5) + ACE_DEBUG ((LM_DEBUG, + "TAO (%P|%t): SL2_AccessDecision::remove_object(%s) " + "object not found in access map\n", + (const char*)key)); + } + else + { + if (TAO_debug_level > 0) + ACE_DEBUG ((LM_DEBUG, + "TAO (%P|%t): SL2_AccessDecision::remove_object(%s) " + " unexpected error during unbind from map (errno=%d\n)", + (const char*)key, + errno)); + throw + CORBA::UNKNOWN (CORBA::SystemException::_tao_minor_code (TAO::VMCID, + errno), + CORBA::COMPLETED_NO); + } + } +} + +CORBA::Boolean +TAO::Security::AccessDecision::default_decision (void) + ACE_THROW_SPEC ((::CORBA::SystemException)) +{ + return this->default_allowance_decision_; +} + +void +TAO::Security::AccessDecision::default_decision (CORBA::Boolean d) + ACE_THROW_SPEC ((::CORBA::SystemException)) +{ + this->default_allowance_decision_ = d; +} + +TAO_END_VERSIONED_NAMESPACE_DECL diff --git a/TAO/orbsvcs/orbsvcs/Security/SL2_SecurityManager.h b/TAO/orbsvcs/orbsvcs/Security/SL2_SecurityManager.h new file mode 100644 index 00000000000..66af6656715 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Security/SL2_SecurityManager.h @@ -0,0 +1,206 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file SL2_SecurityManager.h + * + * $Id$ + * + * @author Chris Cleeland + */ +//============================================================================= + + +#ifndef TAO_SL2_SECURITY_MANAGER_H +#define TAO_SL2_SECURITY_MANAGER_H + +#include /**/ "ace/pre.h" +#include "orbsvcs/Security/security_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "orbsvcs/SecurityC.h" +#include "orbsvcs/SecurityLevel2C.h" + +#include "tao/LocalObject.h" + +#include "ace/Hash_Map_Manager_T.h" +#include "ace/Null_Mutex.h" + +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:4250) +#endif /* _MSC_VER */ + + +TAO_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace TAO +{ + // would prefer SL2, but all the other SL2 stuff is in the Security namespace + namespace Security + { + // This should move out of here probably, but it's easier to stick it + // here for the moment...(CJC) + /** + * @class AccessDecision + * + * @brief + */ + class AccessDecision + : public virtual TAO::SL2::AccessDecision, + public virtual TAO_Local_RefCounted_Object + { + public: + /*! Constructor */ + AccessDecision (/* not yet known */); + ~AccessDecision (void); + + virtual ::CORBA::Boolean access_allowed ( + const ::SecurityLevel2::CredentialsList & cred_list, + ::CORBA::Object_ptr target, + const char * operation_name, + const char * target_interface_name + ) + ACE_THROW_SPEC ((::CORBA::SystemException)); + + virtual ::CORBA::Boolean default_decision (void) + ACE_THROW_SPEC ((::CORBA::SystemException)); + virtual void default_decision (::CORBA::Boolean d) + ACE_THROW_SPEC ((::CORBA::SystemException)); + + virtual void add_object (::CORBA::Object_ptr obj, + ::CORBA::Boolean allow_insecure_access) + ACE_THROW_SPEC ((::CORBA::SystemException)); + virtual void remove_object (::CORBA::Object_ptr obj) + ACE_THROW_SPEC ((::CORBA::SystemException)); + + private: + /*! + * This is the default value that's returned from access_allowed() + * when the access table doesn't contain an entry for the reference. + */ + ::CORBA::Boolean default_allowance_decision_; + + /*! + * Map containing references and their designated insecure access. + */ + // What sorts of maps are available in ACE? We'll be mapping + // an object reference to a boolean, basically. Looks like for + // now we'll map a stringified IOR to the boolean, and provide some + // (for now) simple keys and functions for comparing them. + // + // Locking on this needs to be exclusive to add_object, + // remove_object, and access_allowed. I think that the lock on the + // map itself will be sufficient, but we'll model this after the + // Active Object map in the POA...so whatever way that goes, so, too, + // will this. + typedef CORBA::String_var OBJECT_KEY; + // This is typedef'd because we might try to do something fancier + // where, rather than having just a string as the key, we have a + // structure and the structure precomputes some of the information + // for the actual key. Thus, we could then customize the hash and + // comparison functors so that they use the precomputed information + // rather than computing it each time. For now, though, I want to + // make this easy to get things working. + typedef ACE_Hash_Map_Manager_Ex, + ACE_Equal_To, + ACE_Null_Mutex> // not sure this is right + ACCESS_MAP_TYPE; + + ACCESS_MAP_TYPE access_map_; + + // Lock for accessing the map. It may be possible to get away with + // just using a lock directly in the map, but I'm not sure, so I'll err + // conservatively. + TAO_SYNCH_MUTEX map_lock_; + + private: + /*! + * @brief Encapsulates a TAO-specific way to do object_to_string() without having an ORB reference handy. + * + * @note If OBJECT_KEY changes as described above, this should change + * so that it generates an OBJECT_KEY. + */ + OBJECT_KEY map_key_from_objref (CORBA::Object_ptr obj); + }; + + /** + * @class SecurityManager + * + * @brief + * + */ + class SecurityManager + : public virtual SecurityLevel2::SecurityManager, + public virtual TAO_Local_RefCounted_Object + { + public: + + /// Constructor + SecurityManager (/* not sure what's needed yet */); + + /** + * @name SecurityLevel2::SecurityManager Methods + * + * Methods required by the SecurityLevel2::SecurityManager + * interface. + */ + //@{ + virtual ::Security::MechandOptionsList* supported_mechanisms () + ACE_THROW_SPEC ((CORBA::SystemException)); + virtual SecurityLevel2::CredentialsList* own_credentials () + ACE_THROW_SPEC ((CORBA::SystemException)); + virtual SecurityLevel2::RequiredRights_ptr required_rights_object () + ACE_THROW_SPEC ((CORBA::SystemException)); + virtual SecurityLevel2::PrincipalAuthenticator_ptr principal_authenticator () + ACE_THROW_SPEC ((CORBA::SystemException)); + virtual SecurityLevel2::AccessDecision_ptr access_decision () + ACE_THROW_SPEC ((CORBA::SystemException)); + virtual SecurityLevel2::AuditDecision_ptr audit_decision () + ACE_THROW_SPEC ((CORBA::SystemException)); + virtual SecurityLevel2::TargetCredentials_ptr get_target_credentials (CORBA::Object_ptr o) + ACE_THROW_SPEC ((CORBA::SystemException)); + virtual void remove_own_credentials (SecurityLevel2::Credentials_ptr creds) + ACE_THROW_SPEC ((CORBA::SystemException)); + virtual CORBA::Policy_ptr get_security_policy (CORBA::PolicyType policy_type) + ACE_THROW_SPEC ((CORBA::SystemException)); + //@} + + protected: + + /// Destructor + /** + * Protected destructor to enforce proper memory management + * through the reference counting mechanism. + */ + virtual ~SecurityManager (void); + + private: + + /// The ORB-specific SecurityLevel2::PrincipalAuthenticator + /// reference. + // Except we're not going to have one of these right now + SecurityLevel2::PrincipalAuthenticator_var principal_authenticator_; + + // AccessDecision instance + SecurityLevel2::AccessDecision_var access_decision_; + }; + + } // End SL3 namespace +} // End TAO namespace + +TAO_END_VERSIONED_NAMESPACE_DECL + + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif /* _MSC_VER */ + +#include /**/ "ace/post.h" + +#endif /* TAO_SL2_SECURITY_MANAGER_H */ diff --git a/TAO/orbsvcs/orbsvcs/Security/Security_ORBInitializer.cpp b/TAO/orbsvcs/orbsvcs/Security/Security_ORBInitializer.cpp index e7830c498cc..6f52713d2dd 100644 --- a/TAO/orbsvcs/orbsvcs/Security/Security_ORBInitializer.cpp +++ b/TAO/orbsvcs/orbsvcs/Security/Security_ORBInitializer.cpp @@ -7,7 +7,10 @@ ACE_RCSID (Security, "$Id$") -// #include "Security_Current.h" +#if 1 +#include "orbsvcs/Security/Security_Current.h" +#include "orbsvcs/Security/SL2_SecurityManager.h" +#endif #include "orbsvcs/Security/SL3_SecurityCurrent.h" #include "orbsvcs/Security/SL3_CredentialsCurator.h" #include "orbsvcs/Security/SL3_SecurityManager.h" @@ -42,36 +45,57 @@ TAO::Security::ORBInitializer::pre_init ( throw CORBA::INTERNAL (); } -// // Reserve a TSS slot in the ORB core internal TSS resources for the -// // thread-specific portion of Security::Current. -// size_t old_tss_slot = tao_info->allocate_tss_slot_id (0 -//); + // Reserve a TSS slot in the ORB core internal TSS resources for the + // thread-specific portion of Security::Current. + size_t tss_slot = tao_info->allocate_tss_slot_id (0 /* no cleanup function */); -// CORBA::String_var orb_id = info->orb_id (); +#if 1 -// // Create the SecurityLevel2::Current object. -// SecurityLevel2::Current_ptr current = SecurityLevel2::Current::_nil (); -// ACE_NEW_THROW_EX (current, -// TAO_Security_Current (old_tss_slot, orb_id.in ()), -// CORBA::NO_MEMORY ( -// CORBA::SystemException::_tao_minor_code ( -// TAO::VMCID, -// ENOMEM), -// CORBA::COMPLETED_NO)); +#if 0 // why am I getting a BAD_OPERATION from no SSL context?! + CORBA::String_var orb_id = info->orb_id (); -// SecurityLevel2::Current_var security_current = current; + // Create the SecurityLevel2::Current object. + SecurityLevel2::Current_ptr current = SecurityLevel2::Current::_nil (); + ACE_NEW_THROW_EX (current, + TAO_Security_Current (tss_slot, orb_id.in ()), + CORBA::NO_MEMORY ( + CORBA::SystemException::_tao_minor_code ( + TAO::VMCID, + ENOMEM), + CORBA::COMPLETED_NO)); -// // Register the SecurityLevel2::Current object reference with the -// // ORB. -// info->register_initial_reference ("SecurityCurrent", -// security_current.in () -//); + SecurityLevel2::Current_var security_current = current; - // Reserve a TSS slot in the ORB core internal TSS resources for the - // thread-specific portion of SecurityLevel3::SecurityCurrent - // object. - size_t tss_slot = tao_info->allocate_tss_slot_id (0); + // Register the SecurityLevel2::Current object reference with the + // ORB. + info->register_initial_reference ("SecurityCurrent", + security_current.in ()); +#endif + /* + * Instantiate and register the SecurityLevel2::SecurityManager + */ + SecurityLevel2::SecurityManager_ptr manager2; + ACE_NEW_THROW_EX (manager2, + TAO::Security::SecurityManager (/*need args*/), + CORBA::NO_MEMORY ( + CORBA::SystemException::_tao_minor_code ( + TAO::VMCID, + ENOMEM), + CORBA::COMPLETED_NO)); + + SecurityLevel2::SecurityManager_var security_manager2 = manager2; + + // Register the SecurityLevel2::SecurityManager object reference + // with the ORB. + info->register_initial_reference ("SecurityLevel2:SecurityManager", + security_manager2.in ()); + +#endif + // Rather than reserve another TSS slot in the ORB core internal TSS + // resources for the thread-specific portion of + // SecurityLevel3::SecurityCurrent object, we will re-use the slot + // allocated earlier. // Create the SecurityLevel3::Current object. SecurityLevel3::SecurityCurrent_ptr current3; diff --git a/TAO/orbsvcs/orbsvcs/SecurityLevel2.idl b/TAO/orbsvcs/orbsvcs/SecurityLevel2.idl index 4826c449ed4..6a13faa6877 100644 --- a/TAO/orbsvcs/orbsvcs/SecurityLevel2.idl +++ b/TAO/orbsvcs/orbsvcs/SecurityLevel2.idl @@ -271,4 +271,23 @@ module SecurityLevel2 { #pragma prefix "" +module TAO { + module SL2 { + local interface AccessDecision : SecurityLevel2::AccessDecision + { + /*! Default value returned when a reference is not in the list. */ + // Can't come up with a good name for this. + attribute boolean default_decision; + + /*! Establish whether a particular object can be accessed via insecure + means. */ + void add_object (in Object obj, + in boolean allow_insecure_access); + void remove_object (in Object obj); + + // Should there be some kind of "find" interface? + }; + }; +}; + #endif /* _SECURITY_LEVEL_2_IDL_ */ -- cgit v1.2.1