Protecting sensitive information in Notes documents
Even in the most social businesses there is information that is available only on a "need to know" basis. Sometimes it is only a small subset of the fields in a document. In a Notes client, as long as I can see a document, I can see all the item values in it (using the document properties box), even if the field is hidden in the current form. So what are my options to protect a few sensitive fields?:
XPages simply woud use 2 data sources and save us the trouble of building a dialog box.
As usual YMMV
- Encrypt the fields with an encryption key that only the authorised user have. Problem here: you need to manage these keys and need a different set for each use case - messy. Also you can't show any of these fields in a view
- Hide the database design when applying the template. Looks good on the first view, but a semi skilled user can easily bypass that (e.g. copy & paste into an empty database, create a private view, use a @Prompt smart icon, use the free Document viewer or NotesPeek) - security by obscurity never works
- Store the sensitive data in a second document that is protected by reader names that are different (more restrictive) than the main document. This approach also keeps (given you have security set) curious admins out, a capability RDBMS is lacking
- Change the process and remove the need for the fine grained access control
@If (RiskAssessmentID= "";@Return ( "n/a" ); "" );
tmp := @GetDocField (RiskAssessmentID; "RiskAssessment" );
@If ( @IsError (tmp ); "nothing to retrieve";tmp )
To create such a "secondary document" a few lines of LotusScript in a button make it a seamless experience:
tmp := @GetDocField (RiskAssessmentID; "RiskAssessment" );
@If ( @IsError (tmp ); "nothing to retrieve";tmp )
Sub Click (Source As Button )
Dim doc As NotesDocument
Dim riskDoc As NotesDocument
Dim uiDoc As NotesUIDocument
Dim db As NotesDatabase
Dim w As New NotesUIWorkspace
Set uidoc = w. CurrentDocument
Set doc = uidoc. Document
If doc. IsNewNote Then
Call doc. Save ( True, True )
End If
Set db = doc. ParentDatabase
If doc. RiskAssessmentID ( 0 ) = "" Then
Set riskDoc = db. CreateDocument
Call riskDoc. ReplaceItemValue ( "Form", "RAF" )
Else
Set riskDoc = db. GetDocumentByUNID (doc. RiskAssessmentID ( 0 ) )
If riskDoc Is Nothing Then
Set riskDoc = db. CreateDocument
Call riskDoc. ReplaceItemValue ( "Form", "RAF" )
End If
End If
Call riskDoc. MakeResponse (doc )
If w. DialogBox ( "RAF", True, True, False, False, False, False, "Please provide your Risk Assessment",riskDoc, True ) Then
Call riskDoc. Save ( True, True )
Call doc. ReplaceItemValue ( "RiskAssessmentID",riskDoc. UniversalID )
Call doc. Save ( True, True )
End If
Call uidoc. Refresh
End Sub
To keep the 2 documents in sync we add some code into the PostSave event of the main form:
Dim doc As NotesDocument
Dim riskDoc As NotesDocument
Dim uiDoc As NotesUIDocument
Dim db As NotesDatabase
Dim w As New NotesUIWorkspace
Set uidoc = w. CurrentDocument
Set doc = uidoc. Document
If doc. IsNewNote Then
Call doc. Save ( True, True )
End If
Set db = doc. ParentDatabase
If doc. RiskAssessmentID ( 0 ) = "" Then
Set riskDoc = db. CreateDocument
Call riskDoc. ReplaceItemValue ( "Form", "RAF" )
Else
Set riskDoc = db. GetDocumentByUNID (doc. RiskAssessmentID ( 0 ) )
If riskDoc Is Nothing Then
Set riskDoc = db. CreateDocument
Call riskDoc. ReplaceItemValue ( "Form", "RAF" )
End If
End If
Call riskDoc. MakeResponse (doc )
If w. DialogBox ( "RAF", True, True, False, False, False, False, "Please provide your Risk Assessment",riskDoc, True ) Then
Call riskDoc. Save ( True, True )
Call doc. ReplaceItemValue ( "RiskAssessmentID",riskDoc. UniversalID )
Call doc. Save ( True, True )
End If
Call uidoc. Refresh
End Sub
Sub Postsave (Source As Notesuidocument )
Dim doc As NotesDocument
Dim riskDoc As NotesDocument
Dim db As NotesDatabase
Set doc = source. Document
If doc. RiskAssessmentID ( 0 ) = "" Then
Return
End If
Set db = doc. ParentDatabase
Set riskDoc = db. GetDocumentByUNID (doc. RiskAssessmentID ( 0 ) )
Call riskDoc. ReplaceItemValue ( "Subject",doc. subject )
'Repeat with other fields needed in views, for workflow and access control
Call riskDoc. Save ( True, True )
End Sub
We are almost done. The response documents need some handling when we try to open them.Ideally instead of opening the response we would open the main document. The code in the view's QueryOpenDocument event takes care of that:
Dim doc As NotesDocument
Dim riskDoc As NotesDocument
Dim db As NotesDatabase
Set doc = source. Document
If doc. RiskAssessmentID ( 0 ) = "" Then
Return
End If
Set db = doc. ParentDatabase
Set riskDoc = db. GetDocumentByUNID (doc. RiskAssessmentID ( 0 ) )
Call riskDoc. ReplaceItemValue ( "Subject",doc. subject )
'Repeat with other fields needed in views, for workflow and access control
Call riskDoc. Save ( True, True )
End Sub
Sub Queryopendocument (Source As Notesuiview, Continue As Variant )
Dim id As String
Dim Doc As NotesDocument
Dim parentDoc As NotesDocument
Dim db As NotesDatabase
Dim ws As New NotesUIWorkspace
Dim s As New NotesSession
id = Source. CaretNoteID
If id = "" Then
Continue = True
Exit Sub
End If
Set db = s. CurrentDatabase
Set doc = db. GetDocumentByID (id )
If Not doc. IsResponse Then
continue = True
Exit Sub
End If
continue = False
Set parentDoc = db. GetDocumentByUNID (doc. ParentDocumentUNID )
Call ws. EditDocument ( False,parentDoc )
End Sub
You also need to take care of deletion of documents. Only a user who can see both should be allowed to delete them (or you "flag" them for deletion and let a background agent do the actual deletion). I leave this to you as an exercise. In a real world application you would of course pack all these code into LotusScript objects that live in a ScriptLibrary.
Dim id As String
Dim Doc As NotesDocument
Dim parentDoc As NotesDocument
Dim db As NotesDatabase
Dim ws As New NotesUIWorkspace
Dim s As New NotesSession
id = Source. CaretNoteID
If id = "" Then
Continue = True
Exit Sub
End If
Set db = s. CurrentDatabase
Set doc = db. GetDocumentByID (id )
If Not doc. IsResponse Then
continue = True
Exit Sub
End If
continue = False
Set parentDoc = db. GetDocumentByUNID (doc. ParentDocumentUNID )
Call ws. EditDocument ( False,parentDoc )
End Sub
XPages simply woud use 2 data sources and save us the trouble of building a dialog box.
As usual YMMV
Posted by Stephan H Wissel on 04 November 2011 | Comments (1) | categories: Show-N-Tell Thursday