Das aktuelle Sicherheitskonzept ist pro User. Es wird festgelegt welche Lifecycle Objekte ein Benutzer verwenden darf. Um auch noch zu definieren welche Objekte oder Actions innerhalb dieser Lifecycle Objekte aufrufbar sind muss JVx erweitert werden, da es im Moment nicht vorgesehen ist.
Der aktuelle Ansatz ruht daher, daß ein Entwickler eher ungerne konfiguriert und lieber programmiert. Daher sollten Dinge wie Berechtigungen auch simpel bleiben und am besten automatisch funktionieren. Wenn ein Entwickler jeden Zugriff konfigurieren kann/soll oder sogar müsste dann wird es schnell langweilig und unübersichtlich.
Aber wenn es sein muss, daß Zugriffe bis auf Objekte und Actions geprüft werden und der aktuelle Lifecycle-Check nicht ausreicht, dann kann der aktuelle Mechanismus nicht so ohne weiteres "umgebogen" werden, da die Aufrufe im Framework an den richtigen Stellen fehlen. Der Aufwand hängt von der Umsetzungsvariante ab und beginnt bei wenigen Stunden ist aber ohne weiteres machbar.
Wenn der aktuelle Lifecycle Check ausreicht dann kann eine einfache Lösung auch schnell umgesetzt sein, z.B.: In der Datenbank eine Tabelle für SCREENS erstellen mit Name, Klassenname und Lifecyclename. Eine Tabelle mit Roles für die gewünschten Rollen. Eine Tabelle für die Beziehung der Rollen und Screens. Eine Tabelle für die Beziehung der Rollen und User. Dann kann die V_ACCESSRULES ganz einfach aufgrund der Rollen und User Beziehung die notwendigen Lifecycle Objekte liefern.
Die Application müsste dann beim Login die Screens des aktuellen Users ermitteln um das Menü dynamisch anzupassen um nicht immer alle Screens anzuzeigen. Weiters könnten die Rollen des Users ausgelesen werden um in der Applikation zur Verfügung zu stehen.
Der beschriebene Ansatz wurde in JVx bereits vorgesehen und ist im Interface
com.sibvisions.javax.rad.IWorkScreenApplication bereits definiert:
- Code: Select all
public boolean hasRole(String pRoleName);
Für die Umsetzung braucht es allerdings eine neue Application Implementierung, da die aktuelle Application die Screens nicht dynamisch lädt bzw. öffnet.
Die Klassen SecurityManager, AccessController und ObjectProvider sind reine Server Objekte und haben keine UI Verbindung.
Der SecurityManager übernimmt die Authentifizierung des Clients bzw. einer MasterConnection. Die Authentifizierung kann z.B gegen die DB geprüft werden oder LDAP oder mit OAuth usw.
Der SecurityManager liefert einen AccessController mit dem in einer Session geprüft wird ob das definierte Lifecycle Objekt verwendet werden darf.
Der ObjectProvider wird von der Session aufgerufen wenn ein Objekt bzw. eine Action aufgerufen werden soll. Im Prinzip ist der ObjectProvider ein Container für Lifecycle Objekte und steuert den Zugriff auf diese Objekte.
Um auf Objekt/Action Zugriff zu prüfen, könnte der ObjectProvider den AccessController des SecurityManagers verwenden bevor ein Aufruf erfolgt.
Der Ansatz "Screen mit unterschiedlichen Objekten" war so gemeint:
Am Client wird eine SubConnection pro Screen geöffnet. Jeder SubConnection wird ein Lifecycle Name gesetzt. Es spricht aber nichts dagegen den selben Screen mit unterschiedlichen SubConnections zu öffnen, sprich gleiche Client Klasse, unterschiedliche Server Klassen.
Da sie im Moment eher an einer schnellen Lösung interessiert sind, könnte ich noch folgenden Vorschlag anbieten:
Die Lifecycle Objekte haben pro Objekt und Action eine Java Methode. Sie können in Lifecycle Objekten jederzeit auf Session Informationen via
SessionContext zugreifen. Jede Session hat
Properties die mit dem Client synchronisiert werden.
Nun wäre es möglich das sie beim Zugriff auf ein Objekt/Action selbst prüfen ob die Berechtigung passt z.B.:
- Code: Select all
//declared in SubSession-Lifecycle Object
public ResourceAccess getResourceAccess()
{
checkAccess("resourceAccess");
ResourceAccess rsa = (ResourceAccess)get("resourceAccess");
if (rsa == null)
{
rsa = new ResourceAccess();
put("resourceAccess", rsa);
}
return rsa;
}
//declared in MasterSession-Lifecycle Object
protected void checkAccess(String pProperty)
{
if (SessionContext.getCurrentSession().getProperty(
IConnectionConstants.PREFIX_SERVER +
IConnectionConstants.PREFIX_SESSION +
"role_admin") != null)
{
throw new SecurityException("Access denied!");
}
}
Um diese Lösung Wasserdicht zu machen müssten reine Server Properties eingesetzt werden, da diese dann nicht zum Client übertragen werden, sprich ein nicht serialisierbares Objekt verwenden um die Rollen zu speichern, z.B.:
- Code: Select all
public DBAccess getDBAccess() throws Exception
{
DBAccess dba = (DBAccess)get("dBAccess");
if (dba == null)
{
IConfiguration config = SessionContext.getCurrentSessionConfig();
dba = DBAccess.getDBAccess(DBSecurityManager.getCredentials(config));
dba.open();
put("dBAccess", dba);
//read roles from database
UserRoles roles = new UserRoles();
roles....
SessionContext.getCurrentSession().setProperty("user-roles", roles);
}
return dba;
}
protected void checkAccess(String pProperty)
{
UserRoles roles = (UserRoles)SessionContext.getCurrentSession().getProperty("user-roles");
if (!roles.isAdmin())
{
throw new SecurityException("Access denied!");
}
}
Etwas Generischer:
Wenn Sie als Basis Klasse für Ihre Lifecycle Objekte ein GenericBean einsetzen, könnten sie von diesem ableiten und die Methoden
- Code: Select all
public Object get(String pName)
public Object invoke(String pMethod, Object... pParams)
überschreiben. Diese Methoden werden verwendet um auf Objekte/Actions zuzugreifen und natürlich können sie auch dort die Security prüfen.
Sie sehen, es gibt viele Lösungen, doch es muss noch einfacher und allgemeiner werden für die Entwickler. Daher wird es auch eine Integration in JVx geben, doch diese ist noch nicht fixiert. Die Lösung wird aber ähnlich den oben beschriebenen sein.
Im Moment ist die Dokumentation zwar sehr vernünftig, doch besser geht immer und es würden die ein oder anderen Themen schon noch hilfreich sein. Da JVx aber kein kommerzielles Framework ist, dauern gewisse Dokus leider etwas länger als andere