Hi everybody!
My customer has decided that all users should be able to promote documents even though they only have Version rights.
We have created our own BOF object (let's call it MyDocument) and my first thought was to override doPromote and use privilege escalation (as described in https://community.emc.com/message/731730#731730) in an EscalatedPromote-method running on the method server with admin rights for users with Version rights. This identified a potential issue when the privileged call to IdfSysObject.doPromote actually was handled by MyDocument.doPromote. I just guessed I could cast my document and make it do sysobjects promote, but that didn't work out. Instead I got a loop where MyDocument.doPromote called my Escalated code which again called MyDocument.doPromote. After some minutes I had opened 400 sessions and I didn't know how to stop it.
Of course, the loop was my bad (I forgot to put the unprivileged user in the privilegeRole-group), but still it's a risky thing to do.
This is the essence of my MyDocument.doPromote():
@Override
protected void doPromote(String state, boolean override, boolean testOnly, Object[] extArguments) throws DfException {
String privilegeRole = "dynamic_promote_role";
if (getPermit() >= IDfACL.DF_PERMIT_WRITE) {
super.doPromote(state, override, testOnly, extArguments);
} else if (getPermit() == IDfACL.DF_PERMIT_VERSION) {
int res = promoteDocByEscalatedPrivileges(state, override, testOnly, privilegeRole);
}
}
The method promoteDocByEscalatedPrivileges() invokes EscalatedPromote.execute() on the method server with the needed arguments. EscalatedPromote.execute() adds the executing user to the privilegeRole-group and calls promoteDoc.
And this is my escalated code:
private void promoteDoc(final string documentId,
final String promoteState,
final boolean promoteOverride,
final boolean promoteTestOnly,
final Object[] promoteExtArgs,
final String inRoleName)
throws DfException{
final IDfSession session = getSessionWithUnprivilegedUser();
try{
AccessController.doPrivileged(new DfPrivilegedExceptionActionInRole<String>(new DfRoleSpec(inRoleName), true,
new PrivilegedExceptionAction<String>() {
public String run() throws DfException {
IDfSysObject document = (IDfSysObject) session.getObject(new DfId(documentId));
document.promote(promoteState, promoteOverride, promoteTestOnly);
return "";
}
}));
}
catch(PrivilegedActionException e){
Exception ex = e.getException();
if(ex instanceof DfException)
throw (DfException)ex;
else
throw new DfException(ex);
}
catch(RuntimeException re){
throw re;
}
}
The user now get's Write-rights in the escalated code and it runs super.doPromote() in line 5 in MyDocument.doPromote() as it should. The next thing that happened is this: HTTP request from 127.0.0.1, invoking LifecycleTransitionOperation.execute(), ARGUMENTS [(...)]
and then:
DfException:: THREAD: http-0.0.0.0-9080-3; MSG: [DM_SYSOBJECT_E_NO_WRITE_ACCESS]error: "No write access for sysobject named 'Lighthouse'."; ERRORCODE: 100; NEXT: null
at com.documentum.fc.client.impl.docbase.DocbaseExceptionMapper.newException(DocbaseExceptionMapper.java:57)
at com.documentum.fc.client.impl.connection.docbase.MessageEntry.getException(MessageEntry.java:39)
at com.documentum.fc.client.impl.connection.docbase.DocbaseMessageManager.getException(DocbaseMessageManager.java:137)
at com.documentum.fc.client.impl.connection.docbase.netwise.NetwiseDocbaseRpcClient.checkForMessages(NetwiseDocbaseRpcClient.java:310)
at com.documentum.fc.client.impl.connection.docbase.netwise.NetwiseDocbaseRpcClient.applyForInt(NetwiseDocbaseRpcClient.java:581)
at com.documentum.fc.client.impl.connection.docbase.DocbaseConnection$6.evaluate(DocbaseConnection.java:1254)
at com.documentum.fc.client.impl.connection.docbase.DocbaseConnection.evaluateRpc(DocbaseConnection.java:1056)
at com.documentum.fc.client.impl.connection.docbase.DocbaseConnection.applyForInt(DocbaseConnection.java:1247)
at com.documentum.fc.client.impl.docbase.DocbaseApi.parameterizedSave(DocbaseApi.java:768)
at com.documentum.fc.client.DfSysObject$1.evaluate(DfSysObject.java:373)
at com.documentum.fc.client.DfSysObject.doSaveImpl(DfSysObject.java:403)
at com.documentum.fc.client.DfSysObject.doSave(DfSysObject.java:206)
at com.documentum.fc.client.DfPersistentObject.saveEx(DfPersistentObject.java:912)
at com.documentum.fc.client.DfPersistentObject.save(DfPersistentObject.java:907)
at com.documentum.server.impl.method.lifecycle.BPCommon.commitStateChange(BPCommon.java:313)
I don't know why this is happening, but it might have something to do with my unsuccessful adding of permissions to dfc.jar? I tried to add this to java.policy:
//Enable privilege escalation
grant codeBase "file:/E:/Documentum/jboss5.1.0/server/DctmServer_MethodServer/lib/*" {
permission com.documentum.fc.client.impl.bof.security.RolePermission "*", "propagate";
};
This gives me the following warning in PolicyTool: Warning: Class not found: com.documentum.fc.client.impl.bof.security.RolePermission
Still, I could not find BPCommon in dfc.jar, so maybe this wasn't my last obstacle after all.
As I don't really feel comfortable with this solution because of the potential loop, I am not sure if I should continue this path or choose another path. I could run promote as a system user as long as I can set the unprivileged user as the modifier (r_modifier) afterwards. Or I could add the unprivileged user to a group with write + change state permission, let the user do the promote and then retract the user from the group afterwards. But this has also a potential security issue.
I was hoping anyone in here has some experience with this issue or any thoughts about what I should do. Any tips or hints are deeply appreciated!