Wie setzt man SecurityContext um SessionContext.getCallerPricipal in bean aufzurufen

kwyjibo_84

Mitglied
Hallo zusammen,

ich würde gerne in einer Stateless-Session-Bean das Principal eines angemeldeten Benutzers auslesen.

Java:
@Resource
SessionContext sessionContext;

public void doSth() {
   Principal p = sessionContext.getCallerPrincipal();
}

ich bekomme aber immer eine Exception sobald ich versuche das Principal aufzurufen:
Code:
java.lang.IllegalStateException: No valid security context for the caller identity
   at org.jboss.ejb3.BaseSessionContext.getCallerPrincipal(BaseSessionContext.java:190)

Mein Client schaut so aus:
Ich hab mir mein eigenes JAAS-LoginModul gebastelt und da kann ich mir auch mein Subject holen (Hinweis: auf ein Passwort wird nicht geprüft, es wird nur der Benutzername im Principal abgelegt):
Java:
LoginContext lc = null;
Subject sb = null;
try {
   lc = new LoginContext("MyAuth", new MyCallbackHandler("Sebastian"));
   lc.login();
   sb = lc.getSubject();
} catch (LoginException e) {
   e.printStackTrace();
}

Nun will ich die Stateless-Session-Bean aufrufen. Dafür dachte ich, muss ich folgendes machen:
Java:
Subject.doAs(sb, new MyAction());

Java:
public class MyAction implements PrivilegedAction {
   public Object run() {
      IMyBean myBean;
      try {
         Properties properties = new Properties();
         properties.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
         properties.put(Context.URL_PKG_PREFIXES, "=org.jboss.naming:org.jnp.interfaces");
         properties.put(Context.PROVIDER_URL, "localhost:1099");
         InitialContext context = new InitialContext(properties);

         myBean= (IMyBeanRemote) context .lookup("MyBean/remote");
         myBean.doSth();
      } catch (Exception e) {
         e.printStackTrace();
      }
      return null;
   }
}

bei doSth bzw. getCallerPrincipal wird aber dann immer die IlligalStateException geworfen.
Was mach ich da falsch?
Müsste ich das eher mit org.jBoss.security.jndi.LoginInitialContextFactory machen? Wie würde das funktionieren?

Eigentlich ist mein Ziel nur, in einer Stateless-Session-Bean herauszufinden, wie der Benutzer heißt, der sich angemeldet hat. Gibt es da vielleicht einen anderen/besseren Weg als über den SessionContext?

Ich Teste das ganze in einer Eclipse-IDE in der ein JBoos 4.2 Server gestartet ist.
Mein Client ist eine einfache Java-Klasse mit einer main-Methode.

Schöne Grüße,
Sebastian
 
Zuletzt bearbeitet:
Hallo,

hast du deiner Applikation mitgeteilt, welche SecurityDomain des JBoss benutzt werden soll?

Grüße
THMD
 
Hallo THMD,

danke für deine schnelle Antwort.

Da haben wir es mal wieder. Da hab ich wohl zu wenig gemacht.

Da stellt sich mir nun die Frage: Wie funktioniert das mit der security-domain? Wo kann ich eine security-domain angeben (login-config.xml von JBoss?) und wie kann ich das der Client-Seite und der Server-Seite sagen? Muss das Annotiert werden oder wird das in die ejb-jar eingetragen?

Danke,
Sebastian
 
Das funktioniert glaub ich doch irgendwie mit:

Code:
<jBoss>
   <security-domain>java:/jaas/mysecuritydomain</security-domain>
</jBoss>

Liegt diese jBoss.xml dann in meinem Meta-Inf Verzeichnis meiner EJB-Applikation?
 
Hallo,

wie du schon richtig vermutest hast, werden die SecurityDomains in der login-config.xml definiert. Dort kannst du dir eine application-policy zusammenstellen, die deinen Vorstellungen entspricht. Insbesondere muss dort das von dir selbstgeschriebene Login-Modul rein. Der Name der application-policy ist dann der Name der SecurityDomain.

Damit deine Anwendung - oder besser deine EJB - jetzt weis, welche Security-Domain benutzt werden soll, kannst du sie als Annotation in der Bean definieren (@SecurityDomain("NAME")) oder über den JBoss spezifischen Deploymentdeskriptor jboss.xml. Die jboss.xml Datei kommt dann in das META-INF deiner ejb-jar.

Dort wird das ganze dann so geschrieben, wie du schon gepostet hast, wobei die Security-Domain dann für alle Beans des jeweiligen jars gilt. Es gibt natürlich auch eine Möglichkeit, dass ganze per Bean zu machen - das sieht dann z.B. so aus
Code:
<jboss>
  <enterprise-beans>
    <session>
        <ejb-name>MyBean</ejb-name>
        <security-domain>java:/jaas/NAME</security-domain>
    </session>
  </enterprise-beans>
</jboss>

Grüße
THMD
 
Danke THMD,

ich hab jetzt in der login-config.xml vom JBoss folgendes eingetragen:

Code:
<application-policy name = "MySecurityDomain">
   <authentication>
      <login-module code = "de.kwyjibo.module.MyLoginModule" flag = "required">
         <module-option name="debug">true</module-option>
      </login-module>
   </authentication>
</application-policy>

Und im META-INFmeiner EJB-Applikation in einer jboss.xml nicht mehr als:
Code:
<jboss>
   <security-domain>MySecurityDomain</security-domain>
</jboss>

Und das scheint auch zu funktionieren denn es kommt (leider) eine Exception:
Code:
javax.ejb.EJBAccessException: Authentication failure
at org.jboss.ejb3.security.Ejb3AuthenticationInterceptor.handleGeneralSecurityException(Ejb3AuthenticationInterceptor.java:68)

Liegt das daran, dass ich den Login über diesen client-seitigen Pseudo-Login mache damit ich mein Subject mit (eigentlich ja nur nem Principal mit dem Benutzername) bekomme, und dieses Subject dann Benutze um mit Subject.doAs(...) meine Bean auf den Client zu holen?

Gibt es eine bessere Möglichkeit bei einem Lookup das selbstgebastelte Principal mitzugeben, dass man dann mit sessionContext.getCallerPrincipal() wieder holen will?

Danke,
Sebastian
 
Hallo,

...
Gibt es eine bessere Möglichkeit bei einem Lookup das selbstgebastelte Principal mitzugeben, dass man dann mit sessionContext.getCallerPrincipal() wieder holen will?
...

das kommt darauf an, was du mit deinem Login-Modul für eine Funktionalität abbildest bzw. noch abbilden willst. Der JBoss hat ja bereits einige vordefinierte Login-Module für die diversesten Anwendungsfälle.

Wenn du wirklich nur den Benutzernamen benötigst und ansonsten nix nutzt, also keine Rollen, Berechtigungen, richtige Passwörter etc. könntest du dir mal das SimpleServerLoginModule anschauen. Wenn du dich bei diesem Modul mit Nutzernamen und Passwort=Nutzernamen anmeldest, bekommt der Principal den Nutzernamen und die default Rollen "user" und "guest".

Um jetzt von einem remote Client drauf zuzugreifen benutzt du bei JBoss 4 im einfachsten Fall die JndiLoginInitialContextFactory als InitialContextFactory, also ungefähr so
Code:
Properties properties = new Properties();
properties.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.security.jndi.JndiLoginInitialContextFactory");
properties.put(Context.URL_PKG_PREFIXES, "=org.jboss.naming:org.jnp.interfaces");
properties.put(Context.PROVIDER_URL, "jnp://localhost:1099");
properties.put(Context.SECURITY_PRINCIPAL, "USERNAME");
properties.put(Context.SECURITY_CREDENTIALS, "USERNAME");

InitialContext context = new InitialContext(properties);

Dadurch wird dir der aufwendige Weg einen Client korrekt über JAAS zu authentifizieren abgenommen :)

So ich hoffe mal das hilft dir ein bischen weiter.

Grüße
THMD
 
Hallo THMD,

das wichtige für mich ist eigentlich nur, dass ich mein eigenes Principal nutzen kann. Ich will also nicht nur den Benutzername mitgeben sondern auch noch andere Sachen. Darum hab ich mir mein eigenes Pricipal gebastelt mit noch ein zwei mehr Methoden als nur getName. Ich würde dann in einer Session-Bean das Principal, dass ich über getCallerPrincipal bekomme auf mein Principal casten damit ich die Informationen wieder auslesen kann.

Würde das funktionieren?

Und danke, dass du dich meinem Problem annimmst.
 
Hallo,

das mit dem eigenen Principal ist prinzipiell kein Problem. Du brauchst dann natürlich ein Loginmodul, welches auch deine eigenen Principals erzeugt, womit du wieder bei einem eigenen Loginmodul bist.

Die einfachste Variante imho ist es, wenn du dir denn Quellcode des JBoss runterlädst und eines der bestehenden Loginmodule deinen Wünschen gemäß erweiterst. Ansonsten gibts in der Administrationsdoku für den JBoss auch nen Abschnitt darüber, wie man sich eigene Loginmodule schreibt.

Grüße
THMD
 
Zurück