G
Gast2
Gast
Gleiches Problem wo hast du die config datei hingetan?
Die kannst du hintun wo du willst, muss diese aber über das Property java.security.auth.login.config angeben.
JAAS Login Configuration File
Ich hab keine ejb-jar.xml ich verwende ejb3.1, da benötige ich keine mehr.In dem EJB Project ist ja eine ejb-jar.xml vorhanden. Zusätzlich muss noch eine jboss.xml erstellt werden. Dort sind dann deine EJB's und Methoden abzusichern. Chapter*1.*J2EE Declarative Security Overview
Hab leider auch noch nicht rausgefunden wie man JBossSX transparent in einen Application Client einbindet.
Stimmt, da geht das ja mit Annotations.Ich hab keine ejb-jar.xml ich verwende ejb3.1, da benötige ich keine mehr.
Das mit der JBoss.xml habe ich nur nicht richtig durchschaut. Brauch ich eine jboss.xml oder reicht das web.xml aus?
Ja ich hab jetzt nur mal den LoginContext aufgerufen.
Exception in thread "AWT-EventQueue-0" javax.ejb.EJBAccessException: Invalid User
at org.jboss.ejb3.security.Ejb3AuthenticationInterceptorv2.invoke(Ejb3AuthenticationInterceptorv2.java:161)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
Warum die JndiLoginInitialContextFactory?
Caused by: javax.security.auth.login.LoginException: Für prototyp sind keine Anmeldemodule konfiguriert.
at javax.security.auth.login.LoginContext.init(LoginContext.java:256)
at javax.security.auth.login.LoginContext.<init>(LoginContext.java:403)
at org.jboss.security.jndi.LoginInitialContextFactory.getInitialContext(LoginInitialContextFactory.java:84)
... 50 more
admin=admin
admin=Admin
prop.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.security.jndi.LoginInitialContextFactory");
prop.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");
prop.put(Context.PROVIDER_URL, "jnp://localhost:1099/");
prop.put(Context.SECURITY_PROTOCOL, "prototyp");
prop.put(Context.SECURITY_CREDENTIALS, "admin");
prop.put(Context.SECURITY_PRINCIPAL, "admin");
// InitialContext ctx = new InitialContext(prop);
// JndiLoginInitialContextFactory initialContextFactory = new JndiLoginInitialContextFactory();
LoginInitialContextFactory initialContextFactory = new LoginInitialContextFactory();
// lookup the account manager bean
Context context = initialContextFactory.getInitialContext(prop);
prototyp {
// jBoss LoginModule
org.jboss.security.ClientLoginModule required
;
};
argh, der InitialContext wird ja auf dem Client ausgeführt. Also wird wieder ein JAAS Aufruf am Client hervorgerufen. Genau das was mir nicht brauchen. Denn JAAS auf clientseite ist unsicher durch die Konfigurierbarkeit, da jemand z.b. eine LdapExtLoginModule durch etwas anderes ersetzen könnte. Gut, da ja JAAS dann die Principals an den Server sendet, macht dieser ja auch noch seine Auth und die gefälschten Daten würden dann natürlich abgelehnt werden. Trotzdem nicht schön, wenn sich dem Hacker die Oberfläche so weit offenbart bis zum ersten EJB Inject. So mal ein bisschen Theorie nebenbei.
JndiLoginInitialContextFactory wär dann eh das richtige. Diese verknüpft die Principals mit der SecurityAssocation, welche dann bei jeden JNDI Lookup zu einen EJB mitgesendet werden sollte. Dann authentifiziert dich der Server jedes Mal.
Also sollte man direkt nach den erzeugen des InitialContext einen Lookup machen, und sei es nur auf eine Dummy EJB, um zu testen ob die Logindaten stimmen. Oder z.B. eine EJB die einem die Rollen zurückliefert, nach der man die Oberfläche aufbauen kann.
prop.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.security.jndi.JndiLoginInitialContextFactory");
prop.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");
prop.put(Context.PROVIDER_URL, "jnp://localhost:1099/");
prop.put(Context.SECURITY_PROTOCOL, "prototyp");
prop.put(Context.SECURITY_CREDENTIALS, "admin");
prop.put(Context.SECURITY_PRINCIPAL, "admin");
JndiLoginInitialContextFactory initialContextFactory = new JndiLoginInitialContextFactory();
Context context = initialContextFactory.getInitialContext(prop);
Exception in thread "AWT-EventQueue-0" javax.ejb.EJBAccessException: Invalid User
Warum hast du da zusätzlich ein [c]new JndiLoginInitialContextFactory();[/c]. Eigentlich sollte [c]Context = new InitialContext(env);[/c] doch reichen? Denn der Konstruktor von InitialContext sollte zur Laufzeit die ContextFactory anhand der env Properties bestimmen und diese Factory aufrufen.
@Resource SessionContext ctx;
Nee schon probiert.Hmm, vl Case Sensitive?
wegen dem Context, füge mal folgendes Feld in deine EJB und versuch dann in einer Methode aufzrufen
Java:@Resource SessionContext ctx;
Füge noch bei der class Definition ein [c]@DeclareRoles("Admin")[/c] hinzu.Nee schon probiert.
Anderes unabhängiges Problem?Aber jetzt muss ich ein Singelton machen mit einer Map<Id?,MeinBean> mhm? Ich muss mal drüber schlafen
Anderes unabhängiges Problem?
Benutze einen Service oder oder Singleton Bean. Dort wird zu jedem User der Kontext gehalten. Bei der Erstellung einer Session (ein SFSB) wird der Kontext angelegt, beim Löschen der Session wird der Kontext gelöscht, d.h. die Sessionbean regelt auch den Lebenszyklus des Kontext. Der User authentifiziert sich mit JAAS und über EJBContext (Java EE 6 ) bekommst du immer den aktuellen User in einem Bean.
ok mitDer User authentifiziert sich mit JAAS und über EJBContext (Java EE 6 ) bekommst du immer den aktuellen User in einem Bean.
@Resource private EJBContext context
context.getCallerPrincipal()
Der Client erstellt eine Session (SFSB), authentifiziert sich gegenüber dem Server.
@Stateful
public class PricePilotSession {
private Object uuid;
@EJB
private ContextContainer container;
@Resource(mappedName="UUIDKeyGeneratorFactory")
private KeyGeneratorFactory generatorFactory;
@PostConstruct
public void create(){
KeyGenerator kg;
try {
kg = generatorFactory.getKeyGenerator();
uuid = kg.generateKey();
} catch (Exception e) {
e.printStackTrace();
}
container.addContext(uuid, new Context());
}
@PreDestroy
public void destroy(){
container.removeContext(uuid);
}
}
public class Context {
public String info;
public String username;
//usw.
}
@Singleton
@Startup
public class ContextContainer {
Map<Integer,Context> map = new HashMap<Integer, Context>();
}
@Stateful
public class AngebotRemoteServiceImpl implements AngebotRemoteService{
@Override
public Set<Angebot> getAngebote() {
// wie bekomme ich jetzt hier die Infos rein???
return angebote;
}
}
public void login(String name, char[] pwd) throws LoginException, NamingException {
prop.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.security.jndi.JndiLoginInitialContextFactory");
prop.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");
prop.put(Context.PROVIDER_URL, "jnp://localhost:1099/");
prop.put(Context.SECURITY_PROTOCOL, "prototyp");
prop.put(Context.SECURITY_CREDENTIALS, pwd);
prop.put(Context.SECURITY_PRINCIPAL, name);
Context context = new InitialContext(prop);
Caused by: java.lang.NoSuchMethodError: javax.annotation.Resource.lookup()Ljava/lang/String;
@SirWayne
Kannst du mir mal deine EAR schicken, irgendwie hab ich Probleme das umzusetzen was wir hier diskutiert haben :bahnhof:
Ja daran scheitert es gerade, ich weiß nich wo ich ansetzen muss. Mir fehlt der Startpunkt.Die Information bekommst du aus dem Principal. Natürlich brauchst du u.U. eine eigene Implementierung.
Ich habe mich mal etwas intensiver mit der JSR-299 beschäftigt und bin zu dem Schluss gekommen, dass es mittleweile wohl eine bessere Lösung gibt. Im Kapitel 6 (Scopes and Contexts) geht es auch um Kontexte, die so funktionieren wie hier gefordert. Im Prinzip gibt es schon eine fertige Implementierung für Webapplikationen. Man muss wohl aber (wenn ich das auf den ersten Blick recht verstanden habe) einen eigenen Context verwenden bzw. dem Bean injecten, der von der Applikation gesteuert wird (im Falle der Webanwendung macht das das Servlet über seinen Session-Lifecycle).
Genau so ein Verhalten will ich =), nur halt mit RMIFor example, if we have a session-scoped bean, CurrentUser, all beans that are called in the context of the same HttpSession will see the same instance of CurrentUser. This instance will be automatically created the first time a CurrentUser is needed in that session, and automatically destroyed when the session ends.
Nicht für RMI. Für Beancalls, egal mit welchem Protokoll.Genau so ein Verhalten will ich =), nur halt mit RMI
Meinst du ich muss einen eigene Scope Annotation machen und dazu einen eigenen Context siehe 5.1?
So habe ich das verstanden. Dürfte nicht allzu schwer sein, denn so einen ähnlichen Context gibt es ja schon. Lediglich die Steuerung des Lebenszyklus müsste noch übernomen werden, denke ich.
/**
* Abstract base class for representing contexts with thread local bean storage
*
* @author Pete Muir
*/
public abstract class AbstractThreadLocalMapContext extends AbstractMapContext
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;
import java.lang.annotation.Inherited;
import java.lang.annotation.Target;
import javax.enterprise.context.NormalScope;
@Target(value = {TYPE, METHOD, FIELD })
@NormalScope
@Inherited
public @interface MyScope
{
}
import java.lang.annotation.Annotation;
import javax.enterprise.context.spi.Context;
import javax.enterprise.context.spi.Contextual;
import javax.enterprise.context.spi.CreationalContext;
public class MyContext extends AbstractThreadLocalMapContext-->Klasse gibts leider{
/**
* Constructor
*/
public MyContext() {
super(MyScope.class);
}
@Override
public String toString() {
String active = isActive() ? "Active " : "Inactive ";
String beanStoreInfo = getBeanStore() == null ? "" : getBeanStore()
.toString();
return active + "session context " + beanStoreInfo;
}
@Override
public void setActive(boolean active) {
super.setActive(active);
}
@Override
public void setBeanStore(BeanStore beanStore) {
super.setBeanStore(beanStore);
}
}
import javax.enterprise.inject.spi.Extension;
public class MyExtension implements Extension{
}
Also ich hab jetzt zwar was selber gebasteltetes hinbekommen mit einem Interceptor, aber ich finds ehrlich gesagt nicht sehr toll...
Außerdem muss ich bei jedem Call die SessionID als Parameter mitgeben, um das Mapping hinzubekommen auch häßlich.
Jemand noch eine bessere Idee?
Das Prinzip ist genau so richtig ok. Woher soll der Server denn sonst den Zusammenhang zur Session, die ja vom Client gepflegt wird, kennen und mit dem Call in Verbindung bringen. Läuft doch in HTTP auch so, nur dass du es nicht mitbekommst (url rewriting oder cookies).
Du kannst aber die Schnittstelle von diesen Metainformationen frei halten, wie es z.B. auch JAAS macht:
Der Client pflegt die ID und deren Lifycycle. Bei jedem Call wird die ID über eine clientseitigen Interceptor an den Call angehängt. Auf dem Server wird die ID mit dem serverseitigen Interceptor ausgewertet und mit dem laufenden (Call Thread) verknüpft.
Ich habe mir Weld noch nicht näher angesehen, würde aber davon ausgehen, dass vieles deiner Arbeit dort schon als API zur Verfügung steht.
public Set<Angebot> getAngebote() {
return angebotRemoteService.getAngebote(sessionId);
}
Das letzte mal habe ich das im JBoss 5 gemacht, ich glaube das ging so:. man konnte den Client-Interceptor-Stack mit der Annotation @RemoteBinding und dem Attribut interceptorStack konfigurieren.
Die Konfiguration definiert über AOP den Interceptorstack. Man kann seinen eigenen Stack von einem vorhandenen ableiten und dann den eigenen Interceptor dazu hängen. Die eigene Konfiguration kann man zu den anderen im JBoss dazu legen, aber man kann sie auch mit der Applikation deployen.
... getAngebote(String sessionID)
getAngebote()
Ok das klingt gut.Ja. Das Interface muss dieses Informationen nicht liefern. Sonst müsstest du ja auch immer den Principal mitliefern.
Du bekommst im Interceptor ein Invocation Objekt mit den Metadaten des Calls. Die kannst du dann einfach anreichern und später wieder auslesen.
Die Konfiguration des Interceptors ist auf der serverseite. Realisiert wird der Interceptor Stack aber über den Bean Stub auf der clientseite.
@Interceptor
public class ClientSessionInterceptor implements Serializable {
private static final long serialVersionUID = 1L;
private Object sessionId = "test";
@AroundInvoke
public Object injectSessionId(Invocation invocation) throws Throwable {
invocation.getMetaData().addMetaData("sessionId", "sessionId", sessionId);
return invocation.invokeNext();
}
}
@Interceptor
public class SessionContextInterceptor implements Serializable {
/**
*
*/
private static final long serialVersionUID = 6606220960433411332L;
@AroundInvoke
public Object injectMap(InvocationContext ic, Invocation invocation) throws Exception {
String sessionId = invocation.getMetaData("sessionId", "sessionId").toString();
Map<String, Object> sessionContextMap = SessionRegistry.getSessionContextMap(sessionId);
}
}
@Stateful
@Interceptors(SessionContextInterceptor .class)
@RemoteBinding(interceptorStack="ClientSessionInterceptor")
public class AngebotRemoteServiceImpl implements AngebotRemoteService {
15:04:45,840 ERROR
[org.jboss.kernel.plugins.dependency.AbstractKernelController] Error installing to Start:
name=vfs:///D:/JBoss/jboss-6.0.0.Final/server/default/deploy/xPP_Prototyp.war_WeldBootstrapBean state=Create: org.jboss.weld.exceptions.DeploymentException: WELD-000069 An interceptor must
have at least one binding, but client.ClientSessionInterceptor has none
Mhm ???:LDie Konfiguration definiert über AOP den Interceptorstack. Man kann seinen eigenen Stack von einem vorhandenen ableiten und dann den eigenen Interceptor dazu hängen.
aber man kann sie auch mit der Applikation deployen.
Wenn ich mich recht erinnere, eine Archiv mit der Endung aop und einem passenden Deskriptor im META-INF.
@Resource
private SessionContext sessionContext;
@AroundInvoke
public Object injectMap(InvocationContext ic) throws Exception {
System.out.println(sessionContext.getCallerPrincipal());
System.out.println(sessionContext.getContextData());
Blätter mal ein paar Seiten zurück. Da hatte ich schon erwähnt, dass man die Prinzipalinformationen mit einer Sessioninformationen anreichern könnte ;-)
Wo die SessionID erzeugt wird, sollte egal sein. Ich würde sagen das ist Geschmackssache.
public class TestLogin extends UsersRolesLoginModule{
@Override
protected Principal getIdentity() {
System.out.println(super.getIdentity());
return super.getIdentity();
}
@Override
protected Principal createIdentity(String name) throws Exception {
System.out.println("createIdentity");
return new MyPrincipal(UUID.randomUUID().toString(), name);
}
}
@Resource
private SessionContext sessionContext;
@AroundInvoke
public Object injectMap(InvocationContext ic) throws Exception {
System.out.println(sessionContext.getCallerPrincipal()); ist immer SimplePrinicpal WARUM=??
SecurityContextAssociation.getSecurityContext().getUtil().getCredential()
EDIT: Spricht was dagegenzu nehmen?Code:SecurityContextAssociation.getSecurityContext().getUtil().getCredential()
Ja ein eigenes Principal wäre optimal gewesen aber irgendwie bekomme ich das ja nicht zum laufen siehe oben.
Vielleicht kann mir fart noch genauer sagen wie er die Principal mit infos anreichern würde
Ist schon etwas länger her und ich versuche mich zu erinnern: ich glaube wir hatten ein eigenes LoginModul und eine eine eigenen Prinicipal-Implementierung. Befüllen und auslesen passierte in den jeweiligen Interceptoren (Client und Server). Die eigentlichen Credentials wurden dann vom Loginmodul ausgewertet.
Wichtig dabei war nur, dass der eigenen Interceptor nach dem SecurityInterceptor des JBoss drankommt, sonst sind die Objekte noch nicht initialisiert ;-)
@Override
protected Group[] getRoleSets() throws LoginException {
SimpleGroup rolesGroup = new SimpleGroup("Roles");
rolesGroup.addMember(new SimplePrincipal("Echo"));
Group callerPrincipal = new SimpleGroup("CallerPrincipal");
callerPrincipal.addMember(this.getIdentity());
Group[] newgroups = { rolesGroup, callerPrincipal };
return newgroups;
}
Sieht auch nach workaround aus ...
Titel | Forum | Antworten | Datum | |
---|---|---|---|---|
G | JBoss6 UnitTest | Application Tier | 21 |