I'm working on an existing j2ee app and am required to remove some vendor specific method calls from the code.
The daos behind a session facade make calls into the ejb container to get the user's id and password - in order to connect to the database. The user id and password part of the initialContext used to connect to the server.
I am able to get the userid using sessionContext.getCallerPrincipal()
Is there anyway to get to the SECURITY_CREDENTIALS used on the server connection or, is there a way to pass information from the server connection into the ejbs (they are all stateless session beans).
This is a large app with both a rich-client and web front end, and in a perfect world I'd be happy to go back and re-architect the entire solution to use J2EE security etc - but unfortunately, that is not realistic.
I can't give you a generic solution, but this is what has worked for us. We have the app server connect to LDAP as a specific user that has the ability to request credentials for other users. Then we have some generic security code that we can use to request a users credentials from inside the session beans, based on the users identity from their initial login (just as you are doing it via getCallerPrincipal()).
We also place the users identity in a thread local variable, so that classes down the call chain from the EJB do not have to be "container aware". They simply access the identity from the thread local and use the security classes to look up user profile information. This also makes it easy to change the implementation for testing, or even something other than LDAP lookups.
Other conveniences we created were a JDBCServiceLocator that retrieves connections with user/password for the current user. So the developer does not have to explicitly code the security lookups at all.
Normally the Java EE security model will not allow the retrieval of the user password, for security reasons. But it depends on the implementation. Some vendors provide methods to retrieve this kind of information, but if you rely on such implementations, be aware that the portability of the application will be compromised.
One common approach is to write a servlet filter to intercept the login request and save a copy of the credentials, to be used later. If your application doesn't use the Java EE security infrastructure, this could be easily implemented. That's because some vendors prevent you from filtering an authentication servlet.
Robin,
Sounds like what I was planning. I figured I'd make a call right after a successful server connection to load the credentials into a threadLocal variable on my connection class. I was hoping there was an easier way - but I guess not.
Related
I have 4 separate software systems which implemented separately using java EE, Spring,hibernate etc.I want to integrate all of them and build a master application. I want to have a single login as well. Now they have their own databases and I want to have a shared single database as well because they have some common information.
What is the best method which can be used to achieve this task with having minimum changes to currently implemented systems?
Do I have to implement a new service layer( eg: using JAX-RS) or something on top of new db to access the new shared database and provide all db access services with business logic to above software systems??
For DataBase:
Spring/hibernate applications support connecting to one database by default. If you want to connect to multiple databases (own db + common db) then you will have to take care of database objects (Jdbc connection + pools + lifecycle/transaction management + other db initialisations) by yourself.
In my opinion DB connection+lifecycle initialisation yourself can be a huge pain and will take away your focus from solving real business cases. I would suggest using a single DB for the applications if possible. Most databases allow you to use file-per-table and even distribute the table files across multiple machines/servers (this is an optimisation).
Code Unification
For Unifying the code base into one (I assume you want to unify the codebases), you can make each application a separate module each with its own resource path. For example if you have Service1, Service2 and Service3 then in your new code base all your Service1 resources will be hosted inside /service1 path, Service2 resources inside /service2 path and so on. To do this you will simply need to modify the Path specifiers in your resource files (usually an #Path annotation).
Q: How to change all the api calls to these services since their path changed?
A: Now if you already pickup the paths to api call for these services from a config file then its great, just change the paths in your config file. Else you can actually start using this config approach, and specify something as below:
In your config file:
api-paths: {
service1: /service1/
service2: /service2/
...
}
Config Unification
You can put all your configs in a single file which most frameworks support. Another option to look at is putting separate config files for each service. For 2nd option take a look at TypeSafe Config Lib. It allows you to use multiple config files with overrides.
Note: In case codebase unification is not needed then use a reverse proxy like nginx. Its just how huge websites like google/fb work. You see a single domain which hides all the microservices behind layers of reverse proxies and a CDN.
For Auth/Login
You can do this in a servlet filter. In your config have an exclusion list, these excluded paths can be accessed without login. For example the /login path must in exclusion list so people can access the login page without login first. Now your servlet filter can implement a simple client cookie + server side session store based auth. You will need a password store as well.
The login flow will be like:
User open /login page
User enters username+password (credentials)
Server receives request for login with credentials. Server checks credentials against its own credential/password store.
If successful then server sends response back to client to set a cookie with some expiry time. If failed then send Http Unauthorised response.
Server stores the cookie in its session store as well (cookies will be stored per-client, user1+chrome=1 cookie, user1+firefox=another cookie, user2+any=another set of cookies)
In further requests the client sends the cookie and server (the servlet filter) verifies against its session store. If verification passes then server allows the api call to work.
If cookie expired or no cookie in request then redirect user to /login. Continue from step-1.
Note: Always hash your credentials on client end before sending on network. On server side store only hashed credentials, no raw text passwords. Also if security is paramount then look at salting your credentials as well.
I think a good aproach for this is to have a Look at netflix technology Stack. There is a project called zuul which Acts as reverse proxy. This proxy can route incoming requests to your underlying Services. This proxy can be the frontdoor to your services where every request only can pass throu if it is authenticated.
Hope this will help a bit.
I have an application deployed to Google App Engine. Within the application, there are 2 roles: standard user, and administrator. I have form based authentication setup, and the URL's that require authentication (for example /admin and /account) are setup to require any role (*), just so I can be sure that Google has authenticated them. I have a filter setup for the admin path as well as the account path that talks to backend business logic to see if the user has an account within my application before forwarding them to the page they requested, or redirecting if necessary.
This seems cumbersome, in that for each request, the filter uses the UserService to get the google user in order to determine whether or not the person authenticated by google has an account within the application. I know that within the context of an application deployed to a traditional application server, I could actually define the application level role required to access a url, and since the application server would know about the roles/users for the application, that would be sufficient, but since google is handling the authentication, would I be correct in assuming that I have to handle the access requirements on a per request basis, as I am now with the use of filters? I chose to use filters to try to keep the actual servlet 'cleaner', so that I know that when a client request reaches the servlet, they have been authenticated and are authorized to access those resources.
Would it be wise to carry that data around (whether a user is authenticated and whether or not they are an admin or standard user) in a session? That's the only other alternative I can come up with. I'm not sure how expensive it is to access the UserService for every single request, because that is in turn accessing the datastore. I would imagine there has to be a better way to handle authentication.
Not really sure if it's an optimal solution but what we do now is store a User session (our own implementation, not GAEs) and we cache it aggressively using Objecitfy's cache feature. That way we only hit the datastore on login/logout and most queries after that are virtually free (because of the use standard session time on our app, cache flush is not really a concern)
So, I'm in the middle of building an application where I want the user to be able to send a link to another user and work on the same data. There is little need to persist the data for more than 15 minutes and I want the application to not have to rely on a database.
I have a few variables which I am currently storing in a HttpSession.
Ideally I'd like to be able to set a parameter "sid" in the URL, and use that to set the session ID on the second client's browser - the one that's received a link with the SID.
Unfortunately, there seems to be no way to change the SID of a current session once it's been set up.
The only solution I've come up with so far is referring to the doGet() with a HttpPost.setHeader("Cookie", "JSESSIONID="+ getSessionId()) method, and getting the data with a specific session that way, but this seems pretty clunky.
Any suggestions?
EDIT
This has seemingly turned into a discussion about the wisdom of setting two users up to have the same session so session vars may be kept the same. Note that a non-db, ie light weight solution was what I was looking for. PHP allows you to arbitrarily set a session ID to do this, but I'm deploying to Tomcat in this instance. Something which allows lightweight sharing of a few parameters, that's it...
What I've done, then, is to set context vars using context.setAttribute(). Ugly as sin, but all I can come up with, unless anyone has any better ideas.
This approach has some security issues because you are simulating [session hijacking] with it 1:
In computer science, session hijacking, sometimes also known as cookie
hijacking is the exploitation of a valid computer session—sometimes
also called a session key—to gain unauthorized access to information
or services in a computer system. In particular, it is used to refer
to the theft of a magic cookie used to authenticate a user to a remote
server. It has particular relevance to web developers, as the HTTP
cookies used to maintain a session on many web sites can be easily
stolen by an attacker using an intermediary computer or with access to
the saved cookies on the victim's computer (see HTTP cookie theft).
Better approach is to set your data in a way that both users can approach it from their sessions. If you are using single server you can do that with some global data within a server. In clustered or cloud environments you'll need some common storage for that (ie. database, global cache, etc.)
EDIT
You are on a right track to share data among two users with different sessions.
There is one context per "web application" per Java Virtual Machine
where an attribute allows a servlet container to give the servlet
additional information.
Attributes are meant to be used to share data inside container among servlets of the same web application.
For clusters:
In the case of a web application marked "distributed" in its
deployment descriptor, there will be one context instance for each
virtual machine. In this situation, the context cannot be used as a
location to share global information (because the information won't be
truly global). Use an external resource like a database instead.
We are planning on developing a layer of REST services to expose services hosted on a legacy system. These services will be used by a classic web application and native mobile phone applications.
This legacy system is secured in such a way that an initial username + password authentication is required (a process that can take 5 to 10 seconds). After the initial authentication, a time-constrained token is returned. This token must then be included in all further requests or else requests will be rejected.
Due to a security requirement, the legacy security token cannot be returned outside of the REST service layer. This means that the REST service layer needs to keep this token in some form of user session, or else the expensive username + password authentication process would need to be repeated for every call to the legacy system.
The REST service layer will be implemented using a Java 6 + Spring 3 + Spring Security 3 stack. At first sight, it looks like this setup will run fine: Spring-based REST services will be secured using a rather standard Spring Security configuration, the legacy security token will be stored in the user's HTTP session and every call will retrieve this token using the user's session and send it to the legacy system.
But there lies the question: how will REST clients send the necessary data so that the user's HTTP session is retrieved properly? This is normally done transparently by the web browser using the JSESSIONID cookie, but no browser is involved in this process. Sure, REST clients could add cookie management to their code, but is this an easy task for all Spring RestTemplate, iPhone, BlackBerry and Android clients?
The alternative would be to bypass the HTTP session at the REST service layer and use some other form of user session, maybe using a database, that would be identified using some key that would be sent by REST clients through a HTTP header or simple request query. The question then becomes, how can Spring Security be configured to use this alternative session mechanism instead of the standard Servlet HttpSession?
Surely I am not the first dealing with this situation. What am I missing?
Thanks!
There's nothing magical about cookies. They're just strings in HTTP headers. Any decent client API can handle them, although many require explicit configuration to enable cookie processing.
An alternative to using cookies is to put the JSESSIONID into the URL. I don't know anything about spring-security, but it seems that that's actually the default for at least some types of URL requests, unless disable-url-rewriting is explicitly set to true . This can be considered a security weakness, though.
Unfortunately authentication is highly problematic -- a bit of a blind spot in terms of web standards and browser implementations. You are right that cookies are not considered "RESTful" but purists, but even on fully-featured browsers avoiding takes quite a bit of hackery, as described in this article: Rest based authentication.
Unfortunately I haven't done any mobile development, so I can't suggest what the best compromise is. You might want to start by checking what authentication models each of your targetted platforms does support. In particular, two main options are:
HTTP authentication (ideally "digest", not "basic")
Cookies
One possibility would be to provide both options. Obviously not ideal from a technical or security point of view, but could have merits in terms of usability.
Is there any way to extend the authentication operation which connects a client application to an EJB, using standard JAAS/container-based security? I'm looking for a way to use more than just a username to authenticate the user (in this case a domain name is also needed). Ideally I'd like to be able to use the SessionContext.getCallerPrincipal() to get access to both the username and the domain name in the EJB.
I'm using Glassfish, if that influences the answer at all. Do I need to create a custom login module/custom realm and what should it do?
Adding authentication mechanisms to an EJB Container is usually a vendor specific task. I don't believe there is a standard way to do it. For Glassfish though, I believe this article will help you set up a SAM (Serve Auth Module) that can handle the authentication in any way you need. http://blogs.oracle.com/enterprisetechtips/entry/adding_authentication_mechanisms_to_the
Keep in mind this is Glassfish specific.