I want to call a remote EJB from a different EJB server. I've Remote EJB's deployed on OpenEJB ,then I will call them from Glassfish HTTPServlet. I know on local EJB i can do #EJB annotation but I want user to "authenticate" remote OpenEJB server from Glassfish servlet.
on OpenEJB:
//OpenEJB server at 192.168.10.12
public class AdminManager {
#RolesAllowed("admin")
public void test() {
System.out.println("Admin called this method");
}
}
Glassfish Servlet
//Glassfish servlet at 192.168.10.10
public class AdminManage extends HttpServlet {
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Properties p = new Properties();
p.put("java.naming.factory.initial", "org.apache.openejb.client.RemoteInitialContextFactory");
p.put("java.naming.provider.url", "ejbd://192.168.10.12:4201");
// user and pass optional
String userName = req.getSession().getAttribute("username");
String password = req.getSession().getAttribute("password");
p.put("java.naming.security.principal", userName );
p.put("java.naming.security.credentials", "password );
final InitialContext ctx = new InitialContext(p);
final AdminManagerRemote myBean = (MyBean) ctx.lookup("AdminManagerRemote");
try {
myBean.test();
} catch(Exception epx) {
resp.sendRedirect(resp.encodeRedirectURL("/login"));
}
}
}
Okay this seems a solution but this is not "good" solution for me.
Everytime authenticating to openejb sucks , like this;
String userName = req.getSession().getAttribute("username");
String password = req.getSession().getAttribute("password");
p.put("java.naming.security.principal", userName );
p.put("java.naming.security.credentials", "password );
And the code is not clean.
I want user to authenticate only once and call ejb methods.
Is there any better solution then this?
Can I combine Glassfish HTTP authentication with remote openEJB authentication?
I mean when user authenticates to Glassfish HTTP server , i want openEJB authenticate as well.
This is really making me mad. what solution is good to escape from spagetti codes?
Two ideas:
Authenticate to OpenEJB when the user logs into Glassfish, store the EJB stub in the user session and reuse it later. I fear you will need to implement some EJB 2.x inteface for the serialization of the stub (so-called handle) to work.
Implement a cache where you store the EJB stubs. If a stub for the given username/password is in the cache, reuse it, if not, authenticate. The cache is a static object, it could be created for instance with Guava's CacheBuilder. This violates the spec (you should not use static to share information between servlets), but since it's a cache, it's not a big deal. It would even work in a cluster.
You can try introducing Service Locator Pattern to eliminate the redundancy in the code & hide the underlying details & complexity of creating initial context, JNDI lookup etc.
You can cache remote home interface EJBHome & then re-use it later when required.
Can refer Core J2EE Patterns - Service Locator documentation for more details.
What about Kerberos ? Someone know kerberos solution ?
Login to all remote servers with TGS.
But there is no sample for that on internet.
And its so evil hard to install kerberos with openldap.
Related
I currently have a number of web applications which access a common service running in JBoss 5.0. The service is very simple, using Guice and POJOs. The web applications are authenticated and know who the user is and what roles they have. When calling the service how should I pass this authentication information to the service?
It would seem the simple approach is to simply add a parameter to the interface to take the user information. Possibly a Subject. But this has the downside of cluttering up the interface with contextual information that isn't specific to the job in hand.
void doSomething(Subject subject, ...) {
}
The alternative I have seen is to use ThreadLocal storage, put the user information in there before making the call and make this accessible via some utility class that the service can use. This cleans up the interface but hides the fact that the client of the service has to set the user information before making the call.
Is there another way of doing this? I get the feeling the AOP may be of use here too but can't quite see how. Is there some "best practice" I am missing? Would EJB help?
This cleans up the interface but hides the fact that the client of the
service has to set the user information before making the call.
True, but if you need to pass something to a particular method across the application then you are defeating the purpose of using Dependency Injection. It's there so that you don't have to pass a bunch of services and objects to other services and objects and so forth, they are created with everything they need.
Is there another way of doing this? I get the feeling the AOP may be
of use here too but can't quite see how. Is there some "best practice"
I am missing? Would EJB help?
The other way of doing this would be to use a single filter on every Servlet that calls the services that need the Subject / User. Set the user in the filter, and clear the user at the end in a try-finally block. In fact, OWASP Esapi uses this style when setting their ThreadLocalUser, it allows the User to be available in every part of the application.
Something like this:
#Singleton
public MyUserFilter extends FilterOfTheMonth {
private final Provider<Authenticator> authProvider;
#Inject
MyUserFilter(Provider<Authenticator> auth) {
this.authProvider = auth;
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws java.io.IOException, ServletException {
try {
// Authenticate and SET the current user utilizing the request and/or
// session objects
authProvider.get().authenticateUser(HttpRequest currentRequest);
// Continue on here along the servlet chain
... other processing
} finally {
authProvider.get().getRidOfCurrentUser();
}
}
}
Have you considered moving the authentication process to the common service? Then you only need the session ID in the common service to identify all information about the user the request is coming from.
I want to implement following solution (described in a image) using Java Web Services
When ever a user request with a valid credentials using web services , a session is created over server and that server (who receives the request ) creates a connection with the other server i.e. Meta Trader's Server.
Here each user has a different session to maintain their connection and a state with meta trader server.
Note:
Currently i am not maintaining any session when a user request instead i am saving the connection object in a
#javax.ws.rs.core.Context
ServletContext servletContext;
MyApplication application = new MyApplication();
servletContext.setAttribute("application", application);
But this solution doesn't serve multiple users naturally. so please anyone has an idea how to solve the issue of serving multiple clients then please reply.
I am using Glassfish and JAX-RS ( Jersery 1.1 ) , JAXB
Simply use the annotation #javax.ws.rs.core.Context to get the HttpServletRequest and use its session within the container in which Jersey is deployed.
The code below is a simple example of a jersey resource that gets the session object and stores values in the session and retrieves them on subsequent calls.
#Path("/helloworld")
public class HelloWorld {
#GET
#Produces("text/plain")
public String hello(#Context HttpServletRequest req) {
HttpSession session= req.getSession(true);
Object foo = session.getAttribute("foo");
if (foo!=null) {
System.out.println(foo.toString());
} else {
foo = "bar";
session.setAttribute("foo", "bar");
}
return foo.toString();
}
}
But you should NOT use RESTful API like this. It meant to be used as web service which is stateless, not web application. Check the following answers which I got the example and advice from
(jersey security and session management)
https://stackoverflow.com/a/922058
https://stackoverflow.com/a/7752250
(How to manage state in JAX-RS?)
https://stackoverflow.com/a/36713305
(Get ServletContext in JAX-RS resource)
https://stackoverflow.com/a/1814788
I have developed a web application. I put session id in hashtable. I want to use this hash table in ejb. Means I want to use this login session in ejb.
Is it possible? How can I do that?
It's not impossible, but you must not do it. Get everything you need from the HttpSession and send it to the EJB as method parameters. For example:
public void doGet(HttpServletRequest request, HttpServletResponse response) {
String foo = (String) request.getSession().getAttribute("foo");
ejbService.doSomething(foo);
}
So - pass the values you need as parameters to methods, through the chain layers of your application.
Security credentials are passed automatically from servlet to EJB. If your user has authenticated to the Web Container then you don't need to do any work yourelf.
In the session bean get the EjbContext as described link text
#Resource
private SessionContext sctx;
and then call methods such as
sctx.getCallerPrincipal();
I have this code to create a configuration of a java client to connect to a JBoss application server:
System.setProperty( "java.security.auth.login.config", "auth.conf" );
LoginContext auth = new LoginContext( "myAuth",
new LoginCallbackHandler( username, password ) );
auth.login();
The file auth.conf contains the following lines:
myAuth {
org.jboss.security.ClientLoginModule required;
};
Now, somewhere else in the code (the LoginContext auth isn't known there) I have an EJB that does a initialContext.lookup( jndiName ) and a narrow() to access a Bean on the JBoss application server. This narrow only succeeds if the login information of the first step was correct.
Question
How does the login information propagate from the LoginContext to the narrow()? I don't see any connection between these two places.
And further, how could I do two or more different logins inside of one client?
I found a nice explanation in the JBoss documentation (chapter 8.4.1):
The login() call only binds the name and password to the JBoss EJB layer of the client. All subsequent EJB calls will use these credentials and pass them to the called EJB method.
I am currently using this WebDAV Java Servlet Implementation, it's as far as I know the smallest and the easiest to use WebDAV java solution that doesn't depend on Tomcat ( Using WebLogic ).
So I would like to extend this to use my underlying security layer which somewhat uses a database connection to authenticate users.
My question is if this is possible? Does the HttpServletRequest even get the Authentication?
Consider the following method header:
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { }
Now I would like to use req.getPrincipal to get the User Principal containing the Username and Password. However, my getPrincipal always returns null even if I set my WebDAV client to Windows Authentication or anything else for that matter.
If you are using your own authentication layer, you need to inject your authentication information to the ServletRequest. This is normally done through a filter and wrapped HttpServletRequest.
You can find a good example in CAS,
http://www.jasig.org/cas
Download the source and look at this class,
org.jasig.cas.client.web.filter.HttpServletRequestWrapperFilter