EJB Application Design

Status
Nicht offen für weitere Antworten.

dojolava

Mitglied
Hi,

da ich den text schon auf englisch geschrieben habe poste ich ihn auch so hier, ich hoffe es ist verständlich worum es mir geht!?

I am looking for some suggestions on the following problem:

In my system are Users and Services and a User has some rights for a Service, how do I keep track of my custom User object inside the ejbcontainer? Do I have to send the userId with each request?

I thought of two solutions:

1) I use one Stateless SessionBean that has a login method that returns a Stateful SessionBean and all subsequent communication is handled by this Bean. Thus I can safe the User object in the Stateful SessionBean and pass it to all other services that are used. What I do not like here, is that this SessionBean has to have ALL possible methods that have to be exposed to the client. Or can I return other SessionBeans that can be used remotelty but not direct. Eg:

StatefulBeanRemote myConn = ((StatelessBeanRemote)ctx.lookup("StatelessBeanRemote")).login();
StatefulSearchBeanRemote search = myConn.getSearchService();
search.search("*");

but ctx.lookup("StatefulSearchBeanRemote") should not be possible in this case.

2) What I initially preferred where multiple SessionBeans, each standing for one Service. E.g. one for Search, one for Accountmanagement and so on. And each of them is exposed by @Remote Interface to the client. But here I have the problem that I do not know who is calling the methods? I only know that the Caller has been logged in by my LoginModule. But to know who it is I would either have to send its username/id on every request or make a login on every SessionBean i use....

How is the "normal" design for this? Does anybody has an example application that shows this? I just cannot find anything on the net, alltough I think this scenario must exist a thousand times....

Any help would be appretiated,
Mathis
 
Zuletzt bearbeitet:

FArt

Top Contributor
Wenn du im Code einen Benutzer benötigst (und gerade kein Loginmodul schreibst) hast du höchstwahrscheinlich einen Denk- und/oder Designfehler.

Der zweite Ansatz ist der richtige. Die Businessmethoden werden so konfiguriert, dass sie für User in bestimmten Rollen zugelassen werden. Den Usern werden Rollen zugewiesen und schon regelt der Container den Zugriff, JAAS sei dank.
Auch die Möglichkeit der Rollenzugehörigkeit am EJBContext isUserInRoll() muss eher selten verwendet werden, eigentlich nur, wenn der Zugriff auf die Methode noch kontextabhängig geregelt werden muss.
 

dojolava

Mitglied
Danke erstmal! Würde ich eben auch gern so machen.

Ein LoginModul habe ich, auch das mit den Rollen klappt wunderbar mit JAAS.

Aber ich muss in meinen Business Methoden auch wissen welcher Benutzer die Methode aufgerufen hat. Das heißt ich müsste sowas wie EJBContext.getCallerPrincipal() benutzen können. Diese Methode gibt aber nicht den Benutzer Principal zurück, sondern nur eine der Rollen/Gruppen, zumindest ist das so im OpenEJB Container.

Wie also kann ich wissen und auch sicher gehen welcher Benutzer gerade zugange ist?

Ich brauche das, weil ich für bestimmte Anwendungsfälle spezielle benutzerabhängige Zugangsberechtigungen habe.

Da muss es doch eine vernünftige Lösung geben oder?

Grüße
 
Zuletzt bearbeitet:

FArt

Top Contributor
Da muss es doch eine vernünftige Lösung geben oder?
Ja, das nennt sich Rollenkonzept.

Ich brauche das, weil ich für bestimmte Anwendungsfälle spezielle benutzerabhängige Zugangsberechtigungen habe.
Grüße
Dafür brachst du aber nicht den Benutzer. Diese Benutzer müssen lediglich eine bestimmte Rolle einnehmen können. Im schlimmsten Fall musst du halt Codeguards verwenden, die mit "isCallerInRole" bestimmte Funktionalitäten ermöglichen.

Der Prinzipal repräsentiert ja den User. Mit getName (ist deprecated) bekommst du sogar den Usernamen, oder?
 

dojolava

Mitglied
Dafür brachst du aber nicht den Benutzer. Diese Benutzer müssen lediglich eine bestimmte Rolle einnehmen können. Im schlimmsten Fall musst du halt Codeguards verwenden, die mit "isCallerInRole" bestimmte Funktionalitäten ermöglichen.
Was genau meinst du mit Codeguards?
Bezüglich der Rollen, ich habe nur zwei, Admin und User. Aber jeder User kann ganz eigene Rechte haben, diese beruhen zB auf LDAP Gruppenzugehörigkeit und der Admin kann jeder LDAP Gruppe Rechte geben. So hat jeder Benutzer im System ganz eigene Rechte. Für den Methodenzugriff reicht mir natürlich zB. @RolesAllowed("User"). Aber ich muss eben den Benuter kennen.
Der Prinzipal repräsentiert ja den User. Mit getName (ist deprecated) bekommst du sogar den Usernamen, oder?
Ja genau das ist das Problem, zumindest im EJB Container OpenEJB von Geronimo (apache) ist die Methode getName() nicht deprecated und liefert eben leider nicht der Benutzernamen, sondern EINEN der Gruppennamen.

Es is so implementiert:

[highlight=Java]
public Principal getCallerPrincipal()
{
ThreadContext threadContext = ThreadContext.getThreadContext();
SecurityContext securityContext = (SecurityContext)threadContext.get(org/apache/openejb/core/security/AbstractSecurityService$SecurityContext);
Set principals = securityContext.subject.getPrincipals();
if(!principals.isEmpty())
return (Principal)principals.iterator().next();
else
return null;
}
[/highlight]

und liefert also den ersten der Principals des Subjects..... :-(

Muss ich mich also nach einem anderen Container umschauen?
 

FArt

Top Contributor
Was genau meinst du mit Codeguards?
Normalerweise kann man die Businessmethoden über Konfiguration (Deploymentdeskriptor) bezüglich Security konfigurieren (oder bei EJB mit @RolesAllowed). Damit legt man fest, welcher User die Methode ausführen darf, indem man die Methode für Rollen öffnet, die der User einnehmen muss.

Was genau meinst du mit Codeguards?
Bezüglich der Rollen, ich habe nur zwei, Admin und User.
Das ist der Fehler. Du benötigst mehrere Rollen, die Adminrolle und verschiedene Userrollen. Vermutlich liegst du richtig, wenn du jeweils eine LDAP-Gruppe auf eine Rolle mappst.

Das gesamte Authorisierungsprinzip beruht auf Rollen, nicht auf Usern!
 

dojolava

Mitglied
Das ist der Fehler. Du benötigst mehrere Rollen, die Adminrolle und verschiedene Userrollen. Vermutlich liegst du richtig, wenn du jeweils eine LDAP-Gruppe auf eine Rolle mappst.

Das Problem ist, daß sich in dem Fall der Benutzer immer erst neu einloggen müsste um Berechtigungen zu bekommen. Und ich brauche auf Methodenebene eigentlich nur die zwei Rollen Admin/User. Alle weiteren Berechtigungen würde ich gerne selber implementieren, da sie sehr feingranular sein müssen. Außerdem müsste ich ja dann an manchen Stellen im Code für jede mögliche Rolle isCallerInRole() aufrufen um all dessen Rollen zu bekommen???! Das macht für mich keinen Sinn.....

Das gesamte Authorisierungsprinzip beruht auf Rollen, nicht auf Usern!

Ja, das soll es auch bei mir, aber mir scheint das JAAS einfach zu eingeschränkt für mich ist.

Ich will einfach wissen wer etwas macht. Und das scheint mit OpenEJB nicht zu gehen, da dort getCallerPrincipal nicht den UserPrincipal sondern nur eine der GroupPrincipals zurückgegeben wird....

Aber danke für deine Hilfe!
 

FArt

Top Contributor
Sorry, aber da liegt ein Verständnisproblem deinerseits vor. Du bist der erste, für den JAAS nicht geeignet ist.
Ich komme noch mal auf mein erstes Posting zurück: Design- und/oder Denkfehler.

P.S.: die User-Rollen-Beziehung ist 1:n, warum sollte sich da ein User neu einloggen müssen?
 

dojolava

Mitglied
Sorry, aber da liegt ein Verständnisproblem deinerseits vor. Du bist der erste, für den JAAS nicht geeignet ist.
Ich komme noch mal auf mein erstes Posting zurück: Design- und/oder Denkfehler.

P.S.: die User-Rollen-Beziehung ist 1:n, warum sollte sich da ein User neu einloggen müssen?

Ich habe das getestet, wenn ein Benutzer A die Rolle R1 hat und eingeloggt ist und ich ihm dann, noch eine weitere Rolle R2 gebe, dann hat er diesen neuen GroupPrincipal erstmal nicht im SecrurityContext, ist ja kalr, weil die GroupPrincipals ja im LoginModul gesetzt werden und dieses nicht erneut aufgerugfen wird. Er muss sich also erneut einloggen, bzw die verbindung erneut aufbauen um diesen R2 Principal zu bekommen.

Oder übersehe ich da etwas? Wenn ja, wäre toll wenn du es mir genauer erklären könntest.

Ich sage nicht das JAAS nicht geeignet ist, nur will ich im laufenden Betrieb die Möglichkeit haben Rechte zu ändern. Und ich möchte den CallerPrincipal wissen, aber das scheint ja ein OpenEJB Problem zu sein...
 

FArt

Top Contributor
Schade, dass man immer erst 10 Posts braucht, bis das eigentliche Problem zutage tritt, um das versucht wird herumzuarbeiten.

Problem ist also, dass du zu Laufzeit dem Benutzer Rollen zuweisen können möchtest.

Jetzt ist die Frage, mit welchem AppServer du arbeitest und mit welcher Konfiguration du läufst, du wärst also vermutlich mit der eigentlichen Problemstellung (also nicht mit dem Userquatsch) im Geronimo-Forum besser aufgehoben.

Funktionierendes Beispiel aus meiner Praxis (dort im JBoss):
Die Benutzer und ihre Rollen werden in einem LDAP-Server verwaltet. Benutzt wird ein angepasstes LdapLoginModule (aus anderen Gründen angepasst). Die Rollen werden grundsätzlich gegen den LDAP-Server abgeglichen, werden also in diesem Fall nicht gecacht...
 
Status
Nicht offen für weitere Antworten.

Ähnliche Java Themen

Neue Themen


Oben