I'm curious whether creating a temporary security context this way affects other existing ones, including in other threads. I hooked into a number of system events using LLIAPI NodeCallbacks and am having an issue with CBModePre when moving a document from one folder to another. Inside my callback I'm creating a temporary Admin context to perform some database queries and then releasing it again, which appears to undefine the fStatus feature of the dapiCtx in the LLIAPI NodeMove function (its value is ? after my callback returns). This in turn makes the LLIAPI CBNodeMove function throw the error "An unknown feature was specified" at the following line:
rtnval = llParent.GetChildMoveOptions(dapiCtx, parentRec, nodeRec, dapiStatus.MoveInfo)
I'm including the relevant extracts from my code below. Can't seem to make heads or tails of what's going on.
Thanks,
Uwe
Tennessee Valley Authority
// my callbackfunction Assoc CBMovePre(DAPINODE node, Dynamic moveInfo = UNDEFINED, Dynamic context = UNDEFINED) Assoc rtnVal String errMsg Dynamic apiError
Integer status = DAPI.OK Boolean ok = TRUE if IsUndefined( rtnVal.OK ) rtnVal.OK = ok rtnVal.ErrMsg = errMsg rtnVal.ApiError = apiError rtnVal.Status = status end // execute business rules Assoc args args.node = node args.moveInfo = Assoc.Copy(moveInfo) args.context = Assoc.Copy(context) $TVABUSINESSRULES.Engine.ProcessEvent("MovePre", args, rtnVal) return rtnValend
function void ProcessEvent(String eventName, Assoc args, Assoc retVal) Assoc event event.name = eventName event.id = $TVABUSINESSRULES.Utils.GenerateUniqueID() event.state = Assoc.CreateAssoc() event.args = args event.adminPrgCtx = $TVABUSINESSRULES.Utils.ImpersonateUser("Admin") // rest of code removed because even if returning right here after creating the impersonation // context the node move will fail; if commenting out the line above it will succeedendfunction Dynamic ImpersonateUser(String name = "Admin", String password = Undefined, String domain = Undefined) String cnctName = $Kernel.SystemPreferences.GetPrefGeneral("DftConnection") Assoc prgAssoc = $LLIApi.PrgSession.CreateNewNamed(cnctName, {name, password, domain}) if prgAssoc.ok return prgAssoc.pSession end return Undefinedend
Uwe,
In the callbacks you need to get the user context from the node itself. Using code like this:
checkVal = $LLIApi.NodeUtil.FindDapiCtx( node )
if ( !checkVal.ok )
ok = FALSE
errMsg = checkVal.errMsg
apiError = checkVal.apiError
else
dapiCtx = checkVal.DapiCtx
prgCtx = dapiCtx.fPrgCtx
If you have the node object then you have the correct user context as well ( at least it should be ). But you should be using that
Simply creating a program context will have unpredictable side behaviours such as:
<![if !supportLists]>- <![endif]>Auditing of events using this created session will be incorrect
<![if !supportLists]>- <![endif]>The new context can bump another context off the cache and in some cases could be the one currently in use if the cache is small enough and multiple ‘local’ sessions are created.
As for effect on the other threads, no, each thread is isolated in these contexts. The dapistatus would be the correct reference is the method above is used.
Regards
David Templeton
OpenText
From: eLink Entry: Content Server Development Forum [mailto:development@elinkkc.opentext.com]Sent: Thursday, December 27, 2012 5:09 PMTo: eLink RecipientSubject: Related question
Related question
Posted byuwradu@tva.gov (Radu, Paul) On 12-27-2012 17:07
// my callback
function Assoc CBMovePre(DAPINODE node, Dynamic moveInfo = UNDEFINED, Dynamic context = UNDEFINED)
Assoc rtnVal
String errMsg
Dynamic apiError
Integer status = DAPI.OK
Boolean ok = TRUE
if IsUndefined( rtnVal.OK )
rtnVal.OK = ok
rtnVal.ErrMsg = errMsg
rtnVal.ApiError = apiError
rtnVal.Status = status
end
// execute business rules
Assoc args
args.node = node
args.moveInfo = Assoc.Copy(moveInfo)
args.context = Assoc.Copy(context)
$TVABUSINESSRULES.Engine.ProcessEvent("MovePre", args, rtnVal)
return rtnVal
function void ProcessEvent(String eventName, Assoc args, Assoc retVal)
Assoc event
event.name = eventName
event.id = $TVABUSINESSRULES.Utils.GenerateUniqueID()
event.state = Assoc.CreateAssoc()
event.args = args
event.adminPrgCtx = $TVABUSINESSRULES.Utils.ImpersonateUser("Admin")
// rest of code removed because even if returning right here after creating the impersonation
// context the node move will fail; if commenting out the line above it will succeed
function Dynamic ImpersonateUser(String name = "Admin", String password = Undefined, String domain = Undefined)
String cnctName = $Kernel.SystemPreferences.GetPrefGeneral("DftConnection")
Assoc prgAssoc = $LLIApi.PrgSession.CreateNewNamed(cnctName, {name, password, domain})
if prgAssoc.ok
return prgAssoc.pSession
return Undefined
[To post a comment, use the normal reply function]
Topic:
Using a temporary Admin PrgCtx - and destroying it
Forum:
Content Server Development Forum
Content Server:
Knowledge Center
David,
Thanks for your quick response. The problem is that some of the operations I perform need elevated permissions that most users don't have. In the sample code I posted it's happening using the Admin ID but in production it would be a service account with Admin privileges. So there really is no way around obtaining an elevated security context. The code for the ImpersonateUser() function I obtained right here in this forum and was in fact suggested by one of the OT support folks, so I would assume it's a supported way of doing things.
Uwe W. Radu
TVA