Quick Tip: Benutzervalidierung durch erneute Passwort-Eingabe

von Thomas Bahn,
assono GmbH, Standort Kiel,

Ich hatte letzte Woche eine "kleine" Anforderung von einem Kunden: Er ist interessiert an der erweiterten kommerziellen Version unseres assono Password-Safes. Aber seine interne Revisionsabteilung hatte noch eine neue Anforderung: Der aktuelle Benutzer sollte vor dem Öffnen eines Dokuments oder beim Kopieren eines Passworts in die Zwischenablage direkt aus einer Ansicht vorher noch einmal sein Notes-Passwort eingeben müssen.

Dafür gibt es ein @Command: ToolsUserLogoff. Wenn es ausgeführt wird, logt es den Benutzer aus. Wenn man dieses Kommando mit etwas Code kombiniert, mit dem man auf den Server zugreift, erscheint der Passworteingabe-Dialog, wie es zum Bespiel hier beschrieben wurde: Forcing user re-entry of passwords for electronic signatures in script.

Dieser Ansatz hat aber für mich drei Nachteile:
1. Er funktioniert nicht offline, also z. B. bei einer lokalen Replik, weil der Serverzugriff notwendig ist, um den Passworteingabe-Dialog zu öffnen.
2. Ich möchte es nutzen, um das Öffnen von existierenden Dokumenten abzusichern. Wenn der Benutzer den Dialog abbricht, wird das Dokument trotzdem geöffnet.
3. Der Formel-Code muss im QueryOpen-Ereignis der Maske eingetragen werden. Dort brauche ich aber zwangsläufig LotusScript.

Also musste ich weiter suchen nach einer Lösung in LotusScript. Und ich wurde fündig bei Eknori, der in 2004 diesen Blog-Eintrag verfasst hat: @Command(ToolsUserLogoff) in Lotus Script.
Diese Lösung muss für die aktuellen Versionen von Notes angepasst werden, weil man sich jetzt nicht mehr mit F5, sondern mit Strg-F5 auslogt.

Ich war immer noch nicht überzeugt, dass dies die bestmögliche Lösung für mein Problem sein sollte. Es ist wegen der Verwendung von Windows-DLLs nicht auf andere Plattformen übertragbar, der Benutzer bleibt ausgeloggt, wenn er den Passworteingabe-Dialog abbricht, es würde wohl auch nicht lokal funktionieren usw.

Ich suchte weiter und fand diese großartige Idee: Mittels Notes C-API auf den privaten Teil der Benutzer-ID-Datei zugreifen, genauer mit der  REGGetIDInfoString-Function mit REGIDGetPrivateKey als infoType.

Vielen Dank an Davy Vanherbergen für
seinen OpenNTF Code Bin-Beitrag (von 2003!): Call
notes password prompt from lotusscript
 

Ich habe seine Idee genommen und auf
"meine Art" neu implementiert. Dabei habe ich unsere C-API-Hilfsfunktionen
genutzt, und ich lasse den Benutzer eine andere ID-Datei auswählen, wenn
die in der notes.ini eingestellte nicht die seine ist.


Function
ValidateCurrentUser As
Boolean

        '/**

        '
* validates current user by letting him enter his password


        '
*


        '
* @return  True, if user has successfully entered his password


        '
*


        '
* @author  Thomas Bahn/assono <tbahn@assono.de>


        '
* @version 2014-09-30


        '
*/



        Const
MAXOUTBUFRLEN% = 4096

       

        Dim
idFileName As
String

        Dim
returnCode As
Integer

        Dim
userNameBuffer As
String*MAXUSERNAME

        Dim
actualLen As
Long

        Dim
currentUserName As
String
               

        Dim
outBufrLen As
String*MAXOUTBUFRLEN

       

        If
Not
IsDebugMode() Then
On
Error
GoTo
errorHandler

       

        ValidateCurrentUser
= False

       

        idFileName
= session.GetEnvironmentString("KeyFileName",
True)

        returnCode
= REGGetIDInfoString(idFileName, REGIDGetName, _

         
      userNameBuffer, MAXUSERNAME, actualLen)

        Call
ShowCAPIErrorIfAnyAndEnd(returnCode, "REGGetIDInfo",
_

         
      NULLHANDLE)

       

        currentUserName
= Left(userNameBuffer,
actualLen - 1)
       

        Do
While
session.UserName <> currentUserName

         
      '
ID file configured in notes.ini is not the ID file of the


         
      '
current user


         
      idFileName = uiws.OpenFileDialog(False,
_

         
              "Wählen
Sie Ihre ID-Datei:"
, "*.ID|",
_

         
              GetNotesDataDirectory(),
idFileName)(0)

         
      returnCode = REGGetIDInfoString(idFileName,
REGIDGetName, _

         
              userNameBuffer,
MAXUSERNAME, actualLen)

         
      Call
ShowCAPIErrorIfAnyAndEnd(returnCode, "REGGetIDInfo",
_

         
              NULLHANDLE)

         
     

         
      currentUserName = Left(userNameBuffer,
actualLen - 1)

        Loop

       

        returnCode
= REGGetIDInfoString(idFileName, REGIDGetPrivateKey, _

         
              outBufrLen,
MAXOUTBUFRLEN, actualLen)

        If
returnCode = -32355
Then

         
      Exit
Function
' user cancelled
dialog


        Else

         
      Call
ShowCAPIErrorIfAnyAndEnd(returnCode, "REGGetIDInfo",
_

         
              NULLHANDLE)

        End
If


        '
when we get here, the user must have entered his password


        '
successfully


        ValidateCurrentUser
= True

        Exit
Function

       

errorHandler:

        If
HandleError() = RESUME_NEXT_LINE Then
Resume
Next

        Exit
Function

End
Function


GetNotesDataDirectory()
ist eine Hilfsfunktion, die das Notes-Datenverzeichnis zurück gibt. Ersetze
diese Funktion durch deine eigene oder einfach eine String-Konstante.

Und passe den Fehlerbehandlungscode
(IsDebugMode()
and HandleError())
entsprechend deinen Standards an.

Ich benötige noch einige Deklarationen (Declarations):

Private Const LIBRARY = "Eintrag utils"

' WORD LNPUBLIC OSLoadString(HMODULE hModule, STATUS StringCode, char far *retBuffer, WORD BufferLength);
Declare Function OSLoadString Lib "nnotes" Alias "OSLoadString" (ByVal hModule As Long, ByVal stringCode As Integer, ByVal retBuffer As LMBCS String, ByVal bufferLength As Integer) As Integer

' STATUS LNPUBLIC REGGetIDInfo(char far *IDFileName, WORD InfoType, void far *OutBufr, WORD OutBufrLen, WORD far *ActualLen);
Declare Function REGGetIDInfoString  Lib "nnotes" Alias "REGGetIDInfo" (ByVal idFileName As String, ByVal infoType As Integer, ByVal outBufr As String, ByVal outBufrLen As Integer, actualLen As Long) As Integer
Declare Function REGGetIDInfoBoolean Lib "nnotes" Alias "REGGetIDInfo" (ByVal idFileName As String, ByVal infoType As Integer, ByVal outBufr As Long,   ByVal outBufrLen As Integer, actualLen As Long) As Integer

Const REGIDGetName = 7 ' Data structure returned Is char xx[MAXUSERNAME]
Const REGIDGetPrivateKey = 9 ' Data structure returned Is char xx[xx]


' STATUS LNPUBLIC NSFDbClose(DBHANDLE hDB);
Declare Function NSFDbClose Lib "nnotes.dll" (ByVal hDB As Long) As Integer


Const NOERROR = 0

Const NULLHANDLE = 0&

Const MAXUSERNAME = 256


And two support functions for the C API error handling:

Sub ShowCAPIErrorIfAnyAndEnd(errorCode As Integer, functionName As String, hDB As Long)
        '/**
        ' * shows user the C API error and aborts execution.
        ' *
        ' * @param   errorCode return code of the function's execution
        ' * @param   functionName name of the C API function called
        ' * @param   hDB handle to the open database
        ' *
        ' * @author  Thomas Bahn/assono <tbahn@assono.de>
        ' * @version 2014-07-17
        ' */                
       
        If errorCode = NOERROR Then Exit Sub ' exit if no error occured
       
        If hDB <> 0 Then
                ' if there is a valid handle, try to close database
                Call NSFDbClose(hDB)
        End If
       
        Error Err, "Fehler in Bibliothek '" & LIBRARY & "'" & Chr$(10) & _
        "Ein Fehler ist aufgetreten in der C-API-Funktion'" & _
        functionName & "': "  & Chr$(10) &_
        "Fehler-Code: " & Trim$(Str$(errorCode)) & Chr$(10) & _
        "Fehler-Text: " & Chr$(10) & GetCAPIErrorMsg(errorCode)
End Sub

Function GetCAPIErrorMsg(errorCode As Integer) As String
        '/**
        ' * gets error message for the C API error.
        ' *
        ' * @param   errorCode return code of the function's execution
        ' * @return  error message for the C API error
        ' *
        ' * @author  Thomas Bahn/assono <tbahn@assono.de>
        ' * @version 2014-07-17
        ' */        
       
        Dim length As Integer
        Dim buffer As String
       
        ' initialize a buffer of adequate length to accept the error string
        buffer = String$(256, 0)
       
        ' get the API error message from the internal Notes/Domino string
        ' tables
        length = OSLoadString(NULLHANDLE, errorCode, buffer, Len(buffer))
        If length > 0 Then
                ' remove any trailing characters from the string and
                ' return it to the caller
                GetCAPIErrorMsg = Left$(buffer, InStr(1,buffer,Chr$(0))-1)
        Else
                ' couldn?t locate the error message in the string tables
                GetCAPIErrorMsg = "Unbekannter Fehler"
        End If
End Function

Schließlich platziere Code ähnlich dem folgenden in das QueryOpen-Ereignis deiner Maske:

If continue Then
        continue = ValidateCurrentUser()
       
        If continue Then
                ' do some stuff if necessary
        End If
End If

Da der Code ausschließlich Notes C-API-Aufrufe benutzt, kann er leicht auf weitere Plattformen erweitert werden. Momentan ist er auf Windows beschränkt.

Fachbeitrag IBM Notes Sicherheit Tipp Entwicklung Veranstaltung AdminCamp

Sie haben Fragen zu diesem Artikel? Kontaktieren Sie uns gerne: blog@assono.de

Sie wollen eine individuelle Lösung? Kontaktieren Sie uns

Weitere interessante Artikel

IBM Cognos Analytics 11.0.9 (R9)

IBM Cognos Analytics 11.0.9 (R9)

Erst Mitte November hatten wir über Neuerung in der Version 11.0.8 gebloggt. Knapp ein Monat später veröffentlicht IBM die Version 11.0.9 … Mehr

von
Filip Meyer
,

Sie haben Fragen? Wir sind für Sie da.

Wenn Sie mehr über unsere Angebote erfahren möchten, können Sie uns jederzeit kontaktieren. Sie können uns auf verschiedene Weisen für eine unverbindliche Erstberatung erreichen:

assono GmbH

Standort Kiel (Zentrale)
assono GmbH
Lise-Meitner-Straße 1–7
24223 Schwentinental

Standort Hamburg
assono GmbH
Bornkampsweg 58
22761 Hamburg

Telefonnummern:
Zentrale: +49 4307 900 407
Techn. Hotline: +49 4307 900 403
Vertrieb: +49 4307 900 402

E-Mail-Adressen:
kontakt@assono.de
bewerbung@assono.de