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.
Related
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)
I have created Java Web Application by using Netbeans IDE. I have created entities with relationships. Webpages are simple dashboards where I can add new entities, change them and delete them.
I have added Restful web services to my entities. So web page will be available only for admin and I want to create client application that will have access only for his own data. That means client must login or register to my server.
When user logins/registers on website, server will create session for this user. I know that in RESTful service there is no sessions. My thought is to pass login and password every time when client wants to do some operation with server.
Question: is there any other method to create something like session between client and server? I hope it is not connected with encryption.
There are many options for authentication as well as authorization. If you want to use simple authentication then 'Basic Auth' of HTTP. Check out https://www.rfc-editor.org/rfc/rfc2617 for details. Remember that this is unsafe because the username/password flows on wire. Anyone can sniff username/password. This is updated by new RFC7235 - https://www.rfc-editor.org/rfc/rfc7235#section-4
Safer choice is oAuth. Explained in RFC6749 https://www.rfc-editor.org/rfc/rfc6749. In this case an access token goes with each request.
In both the cases the credential details travel with headers. No interference with parameters.
I have two Java wepapps potentially on different domains/servers using Spring Security for authentication. The first is handling authentication locally storing users in the application database. For the second, I would like to authenticate users using the same users accounts than the first webapp with single sign on (if a user is authenticated in the first webapp, it shouldn't have to enter his info again in the second).
I identified three potential ways to do this but it doesn't seem very straightforward:
Shared cookies: Using a shared session cookie and the same database for the two applications. It seem relatively easy to do but the two webapps need to be on the same domain which isn't necessarily the case for my applications.
Directory service: Using a central directory service (LDAP) which would be used by the two webapps to handle authentication. It seem pretty heavy to implement and the users can't be stored in the first webapp database anymore. The existing users accounts would need to be migrated into the LDAP and it would not be possible to create new users using the first webapp.
OAuth: It seem to be be possible to make the first webapp handle external authentications requests by providing an OAuth api (like Google sign on kind of service). That would allow the second webapp to use this api to authenticate the users, but I'm not sure that the signin process would be totally transparent to handle single sign on. It doesn't seem very easy to implement either, as it would necessitate the development of a complete OAuth api in the first webapp.
I also looked at this service https://auth0.com that seem to provide an authentication api that can be interfaced with an external database, but I'm not sure that it can be interfaced with Spring Security and it also mandate the use of an online solution which isn't ideal. I'm not sure that it would handle single sign on either, only shared accounts.
Is there any other way to handle this use case that would be more straightforward?
CAS is a good candidate indeed as a SSO system for your need and it has several CAS clients for Spring Security. You can try for free a CAS server v4.0 at CAS in the cloud: http://www.casinthecloud.com...
As you mentioned, a shared cookie won't work across domains.
LDAP would give you shared credentials (single name/pw works for both systems), but not single sign on, and you notice you'll have provisioning issues.
Not knowing anything about Spring Security, odds are high you won't find a painless solution to this. Integrating SSO is fraught with workflow issues (user provisioning, password recovery, user profile maintenance, etc.)
We had a classic DB managed authentication scheme. Later, when we added LDAP support, we added the capability for "auto-provisioning". This basically consisted of having the application pull down the relevant demographics from the LDAP store during login, and simply updating fields each time user logged in. If the user didn't exist, we'd create one on the fly.
This worked well, because the rest of the application had no awareness of LDAP. It simply worked with the user profile we managed already and if it needed something from the DB, the data was there.
Later, when we integrated SSO, we just leveraged the existing LDAP logic to pull from the SSO server and do the same thing.
This workflow helped a lot with provisioning and management. We could maintained the authoritative source (LDAP, SSO), and the app just kept up. What it hindered was local editing of the user profile, so we simply disabled that. Let them view the profile, but they could go to the other systems portal for management. Inelegant, but it's a rare use case anyway, so we just muddled through it. We eventually worked out two way pushing and replication, etc. but it's a real pain if you don't need it.
You can look here if you want an overview of how to do cross domain SSO: Cross Domain Login - How to login a user automatically when transferred from one domain to another
For our SSO, we use SAML v2 Web Profile, but we ended up writing our most of our own code to pull it off.
But, bottom line, no matter what the web sites say, integrating this is non-trivial. The edge cases and workflow/help desk issues that surround it are legion. And it can be a bear to debug.
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.
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.