Thank. I'll try to implement this approach in my app.
But: why does my current approach work?
Now I execute Framework.login() one time, when my web-application
(tomcat)
starts. Then, when requests are coming on server-side I simple execute -
CoreInstance.getInstance().open(repository,null);
Every request is executed in own thread. But it not causes security
errors.
Why? (Framework.logout I call when web-app is shutting down)
Alexander.
-----Original Message-----
From: Bogdan Stefanescu [mailto:[EMAIL PROTECTED] Sent: Tuesday,
August 07, 2007 1:39 PM
To: Filipchik Alexander
Cc: 'Nuxeo List'
Subject: Re: [Ecm] Nuxeo security system and Remoting
Filipchik Alexander wrote:
Hello friends.
Now I am investigating your security approach connected to Nuxeo-Remote
framework. I found, that interaction with remote Nuxeo server starts
with calling an Framework.login(username, userpassword).
What is confusing me - it's an static methods.
After I had login in I can create sessions by
CoreInstance.getInstance().open(repository, null).
It's another static method.
Yes they are static - but there is nothing wrong with that.
They act as a facade to simplify API - but inside they call non static
methods.
For example
Framework.login(username, password);
is a shortcut for
Framework.getRuntime().getService(LoginService.class).login(username,
password);
or .. this is the same as
Framework.getLocalService(LoginService.class).login(username, password);
and LoginService.login(...) is not static.
This method is finally calling
LoginContext ctx = new LoginContext(name, handler);
ctx.login();
which is part of java.security API.
There is nothing wrong with being static or not.
Its means that I can't create sessions for several users in one time.
You can but in a thread you can have only one login context at a time.
So if you want to use several logins you need to logout first and then
re-login using a different account
Or you may also use different threads each one using its own login
context.
The problem is that after you logout you need to refetch a new
CoreSession (because the core session you already have was created
in the old login context and you need the new core session to be
validated in the new context)
We already have this working in Apogee (Apogee is a nuxeo ECM rich client
based on Eclipse RCP)
I am currently working on simplifying client environment and connection
configuration.
You can take a look at this project to see examples or to reuse some
modules.
I will explain here how the login is done on the client side to make
things clear for everyone:
To login through a javax.security.auth.LoginContext you need to call:
LoginContext lc = Framework.login(username, password);
This will use lookup right LoginModule to login on Nuxeo ECM server and
will use that module
to perform the login, then it returns the login context:
The login is done as follow:
public LoginContext login(String username, Object credentials)
throws LoginException {
DefaultCallbackHandler handler = new
DefaultCallbackHandler(username,
credentials);
LoginContext ctx = new LoginContext(name, handler);
ctx.login();
return ctx;
}
Later you can logout using the renturned context:
lc.logout();
Now, what exactly happens after the login method is called?
LoginContext ctx = new LoginContext(name, handler);
ctx.login();
This is explained in LoginContext javadoc.
The login configuration will be queried about the login module registered
for the specified security domain (the name argument)
and then the registered login module will be used to perform the login
using the passed credentials.
In our case the security domain name is "nuxeo-client-login" and the
login module registered for this domain
is
org.jboss.security.ClientLoginModule
So finally the Framework.login(username, password) method will end up in
calling the methods
org.jboss.security.ClientLoginModule.login()
and then
org.jboss.security.ClientLoginModule.commit()
This is performing the login specific to a JBoss client
If you look into the code in org.jboss.security.ClientLoginModule you
will se that jboss is doing the login as follows:
public static void pushSubjectContext(Subject subject,
Principal principal, Object credential)
{
SecurityManager sm = System.getSecurityManager();
if (sm != null)
sm.checkPermission(setPrincipalInfoPermission);
// Set the legacy single-value access points
if (server)
{
threadPrincipal.set(principal);
threadCredential.set(credential);
}
else
{
SecurityAssociation.principal = principal;
SecurityAssociation.credential = credential;
}
// Push the subject context
SubjectContext sc = new SubjectContext(subject, principal,
credential);
threadSubjectStacks.push(sc);
if (trace)
log.trace("pushSubjectContext, subject=" + subject + ",
sc="+sc);
}
where threadPrincipal and threadCredential are thread local variable.
What means all this?
It means that in fact when you perform a Framework.login(username,
password)
the login context (username and credentials) are pushed in a thread local
stack attached to the current thread
and the first time you will access a protected bean remotely JBoss will
use the information available in this stack
(by doing a stack.peek).
So the real login (authentication) on the server side is made when you
first access a protected bean and not when you call the login method.
This also means that the login is valid only in the current thread - so
if you are using mutliple threads you need to do for each one a new
login.
This also means that you can perform several login in a thread to switch
the identity and the restore the old login using a logout (which will pop
the current login from the local thread stack).
LoginContext lc1 = Framework.login("u1", "p1");
//... do something
LoginContext lc2 = Framework.login("u2", "p2");
// .. do domething
lc2.logout();
// now we are back in the lc1 context
lc1.logout();
// now we are no more logged in
Note that I have *not* tested this but theoretically it should work.
This also means the login itself is not costly -> it initialize only a
thread local variable and the authentication on the server side is done
later when you access a protected bean.
I hope this will clarify how login works.
If you have more question do not hesitate
Regards,
Bogdan
In my test integration application I create next approach:
1) When my web-app is starting - I init Nuxeo-Remoting (Framework,..)
and
do
login as Administrator.
2) I add and delete documents
3) When I shoot down application - I do logout.
But in this way - I interact with Nuxeo only under Administrator user.
How will I have to change it, to allow permission management on Nuxeo
side?
For example:
1) I add login page into my application
2) When app is starting - I init Nuxeo-remote
3) When I need to add or delete document - I do Framework.login (using
current user credentials), getSession, logout (all in synchronize
section).
Is it right way? If yes - is it good for performance? Can I create an
holder, that can holds session factory each loggined user
to
avoid login/logout actions on each remote call and multi threading
killing?
Alexander
_______________________________________________
ECM mailing list
[email protected]