Transiente Attribute und Zugriffsrechte – be careful

Dezember 1, 2021 0 Von Andreas

Ich bin neulich über etwas gestolpert was zunächst befremdlich, bei genauerer Betrachtung jedoch vollkommen logisch ist. Wenn es nicht auffällt kann es allerdings zu sehr nervigen Fehlern führen deren Gründe sehr schwer zu finden sind. Zugegeben, es handlet sich nicht um ein Problem welches sehr oft auftaucht. Aber umso besser ist es vielleicht schon einmal darüber gelesen zu haben.

Was war passiert?

Im Prinzip handelte es sich um einen Standardprozess. Durch klicken auf einen Button wird ein Microflow ausgelöst. Dieser Microflow erzeugt ein Objekt und initialisiert die Attribute mit Werten. Dieses noch nicht gespeicherte Objekt wird nun einer Seite übergeben auf der der User bestimmte Attribute ändern bzw. setzen kann. Anschließend drückt der Benutzer wieder auf einen Button welcher einen Microflow auslöst in dem das Objekt unter anderem in die Datenbank gespeichert wird.

So weit, so standard. Es kam trotzdem zu unerwarteten Fehlern. Eine genauere Betrachtung im Debugger zeigte, dass ein bestimmtes Attribut zwar im ersten Microflow initialisiert wurde, im zweiten Microflow jedoch wieder den default Wert aus dem Domain Model hatte. Es gab keine Stelle im System an der dieses Attribut veränder oder überschrieben wurde. Auch der Benutzer hatte auf der Page keine Möglichkeit das Attribut zu sehen oder zu verändern. Woher kommt also das Rollback?

Security und der Stateless Server

Um zu verstehen was passiert ist, muss man mit dem Konzept des Stateless Server (welches mit Mendix 7 eingeführt wurde) vertraut sein. In der Kurzfassung bedeutet es, dass der Server am Ende einer durch den Benutzer ausgeführten Microflowcascade den Status von Objekten nicht speichert. Der aktuelle Status der verwendeten Objekte befindet sich im Client (Der Browser des Benutzers) und werden bei jeder neuen Benutzerinteraktion an den Server übertragen. Dieser arbeitet dann mit dem Zustand der vom Client übertragen wurde. Dies hat vor allem Vorteile im Bereich der horizontalen Skalierbarkeit worauf ich hier jetzt nicht im Detail eingehen möchte.

Durch das Speichern des aktuellen Status im Client spielen die Zugriffsrechte eine entscheidende Rolle. Im Client kann nur gespeichert werden was der benutzer sehen darf. Hat ein Benutzer auf ein Attribut keinen lesenden Zugriff, so wird das Attribut nicht an den Client übertragen. Da der Stateless Server jedoch den Status nicht speichert dieser aber aus Sicherheitsgründen auch nicht an den Client übertragen wird, geht dieser verloren.

In oben genanntem Beispiel ist genau das passiert. Der Benutzer hatte auf das Attribut keinen Lesezugriff. Das Attribut musste aber für die Weiterverarbeitung initialisiert sein. Dies hat durch das Client-Server Zusammenspiel nicht funktioniert.

Ein Beispiel

Betrachten wir dieses sehr einfache Domain Model

Die Access Rights sind folgendermaßen definiert

Wie man sieht hat der Benutzer keinen Zugriff auf das HiddenAttribute.

Nun erzeugen wir in einem Microflow ein Objekt und initialisieren es mit Werten. Das HiddenAttribute wird mit dem String ‚Initialized‘ angelegt. Ohne zu committen übergeben wir das erzeugte Objekt nun einer Seite.

Wie man sieht schreibt dieser Microflow die Werte der Attribute ins Log. Führt man auf der Page nun einen Microflow aus welcher nochmals die Werte ins Log schreibt kann man die Unterschiede sehen. Das Ergebnis ist, dass im create Microflow der initialisierte Wert ins Log geschrieben wird. In dem Microflow welcher von der Seite aufgerufen wird ist das Attribut jedoch wieder uninitialisiert. Die Information geht also verloren.

Im Vergleich betrachten wir nun diesen Microflow

Hier wird das Objekt während dem Anlegen committed. Nun verhält sich das System anders. Der initialisierte Wert findet sich auch im Microflow wieder der von der Seite aus ausgeführt wird. Dies als „Lösung“ zu betrachten greift allerdings etwas zu kurz. Unter Umständen möchte man das Objekt zu diesem Zeitpunkt noch nicht committen. Wenn man es doch tut braucht man evtl. eine richtige Rollback Strategie (falls der Benutzer auf Cancel klickt). Es wirft außerdem neue Fragen auf. Was ist z.B. mit einem Objekt welches committet ist und im nachgang verändert wird? Betrachten wir diesen Microflow:

In diesem Microflow wird das Objekt angelegt, initialisiert und committet. Anschließend wird es einmal mit Page Refresh und einmal ohne Page Refresh verändert. Das Ergebnis ist das zu erwartende. Alle Änderungen die nach dem Commit stattfinden gehen verloren.

Fazit

Probleme dieser Art tauchen nicht sehr häufig auf. Es ist trotzdem sinnvoll sich bewusst zu machen, dass es dieses Verhalten gibt. Eine wirkliche „Lösung“ für das Problem gibt es nicht. Es kommt ganz darauf an wie der konkrete Usecase aussieht. In manchen Fällen kann es sinnvoll sein dem Benutzer einfach ein Leserecht einzuräumen. Ist das nicht möglich muss das Objekt committet werden, oder man muss den Wert im Nachgang initialisieren.

Ich hoffe dem ein oder anderen weitergeholfen zu haben. Viel Spaß beim ausprobieren. Ich freue mich wie immer auf Rückmeldung.