Virtualizing Liferay Portal with Proxmox VE
2011/11/23
Some days ago I had to deploy a Liferay Portal in a hosting provider where Proxmox Virtual Environment (PVE) was necessary to use.
Proxmox Virtual Environment is a Debian distro with pre-installed packages ready to use when you want to create virtualization platform for running Virtual Appliances and Virtual Machines based on OpenVZ and KVM.
But, What is difference between tradicional hosting and hosting based on Proxmox VE?, really does not exist differences because with Proxmox VE you can virtualize all (network, server, vlan, etc.).
Then, I did create a virtualized network with 2 servers based on Proxmox, the first server runs a Linux Debian with Apache HTTP server as web-proxy, the second server will be a private server with Liferay Portal.
The architecture final is as follow:
1. Installation first server with Proxmox / Apache2 HTTP Server (In Host)
When installing Proxmox in your hosting provider you will have as principal public server a first server with Debian Linux,
its initial configuration is as follow:
root@kns ~ # nano /etc/network/interfaces ### Hetzner Online AG - installimage # Loopback device: auto lo iface lo inet loopback # device: eth0 auto eth0 iface eth0 inet static address 176.9.30.36 broadcast 176.9.30.63 netmask 255.255.255.224 gateway 176.9.30.33 pointopoint 176.9.30.33 post-up mii-tool -F 100baseTx-FD eth0 # default route to access subnet up route add -net 176.9.30.32 netmask 255.255.255.224 gw 176.9.30.33 eth0
root@kns ~ # more /etc/resolv.conf search nameserver 213.133.100.100 nameserver 213.133.98.98 nameserver 213.133.99.99
After of installing Proxmox, you have to create virtual network with a private IP range, in this case I will use 10.10.10.x.
1.1. Creating Virtual Network with Proxmox
root@kns ~ # nano /etc/network/interfaces
# Loopback device:
auto lo
iface lo inet loopback
# device: eth0
auto eth0
iface eth0 inet static
address 176.9.30.36
broadcast 176.9.30.63
netmask 255.255.255.224
gateway 176.9.30.33
pointopoint 176.9.30.33
post-up mii-tool -F 100baseTx-FD eth0
post-up echo 1 > /proc/sys/net/ipv4/conf/eth0/proxy_arp
#### my new virtual network
auto vmbr0
iface vmbr0 inet static
address 10.10.10.1
netmask 255.255.255.0
bridge_ports none
bridge_stp off
bridge_fd 0
post-up echo 1 > /proc/sys/net/ipv4/ip_forward
post-up iptables -t nat -A POSTROUTING -s '10.10.10.0/24' -o eth0 -j MASQUERADE
post-down iptables -t nat -D POSTROUTING -s '10.10.10.0/24' -o eth0 -j MASQUERADE
root@kns ~ # nano /etc/sysctl.d/10-no-icmp-redirects.conf #### my bridge to VM net.ipv4.conf.all.send_redirects = 0
root@kns ~ # nano /etc/sysctl.conf ### Hetzner Online AG installimage # sysctl config net.ipv4.conf.all.rp_filter=1 net.ipv4.icmp_echo_ignore_broadcasts=1 net.ipv4.ip_forward=1
2. Installation of second server with Liferay 6.0.6 CE (a Guest VM)
2.1. Install your prefered Linux distro in your new VM
With Proxmox VE is easy and quickly to create VM from ISO image.
You can change VM parameters as RAM, HD, type of Network interface, MAC, etc. all from Proxmox VE web interface, or if you know Proxmox’s commands you could do from SSH terminal.
2.2. Configure eth0 in Guest
After of creating your VM with Proxmox, you will need to asign private IP or customize your VM, in this case you will need a VNC terminal to apply these changes.
With Proxmox you can get a shell/terminal to Guest VM without connection to virtualized network.
Then, from Proxmox VE (interface web) go to your recently VM created and open a VNC terminal, then here runs following commands:
[root@pisco ~]# nano /etc/sysconfig/network-scripts/ifcfg-eth0 DEVICE="eth0" NM_CONTROLLED="yes" ONBOOT=yes HWADDR=3E:DB:61:48:63:88 TYPE=Ethernet BOOTPROTO=none IPADDR=10.10.10.12 PREFIX=24 GATEWAY=10.10.10.1 DNS1=213.133.99.99 DEFROUTE=yes IPV4_FAILURE_FATAL=yes IPV6INIT=no NAME="System eth0" UUID=5fb06bd0-0bb0-7ffb-45f1-d6edd65f3e03
[root@pisco ~]# more /etc/resolv.conf search local nameserver 213.133.99.99
…add gateway
[root@pisco ~]# ip route add 176.9.30.36 dev eth0
..add default path
[root@pisco ~]# ip route add default via 176.9.30.36
2.3. Re-start VM and test configuration
[root@pisco ~]# ping www.google.com PING www.l.google.com (74.125.39.103) 56(84) bytes of data. 64 bytes from fx-in-f103.1e100.net (74.125.39.103): icmp_seq=1 ttl=55 time=6.77 ms 64 bytes from fx-in-f103.1e100.net (74.125.39.103): icmp_seq=2 ttl=53 time=6.81 ms
2.4. Install Liferay, then move Liferay to non-root context
Liferay will be running with this URL: http://10.10.10.12:8080/kns
3. Move Proxmox Virtual Environment 1.9 (proxmox’s website) from 80 port to 8080 port.
Next blog post.
4. Configure first server as Reverse Web Proxy
Next blog post.
5. Test installation
From Internet you can call this URL: http://myliferay.intix.info/kns, http://176.9.30.36/kns or http://${YOUR-PUBLIC-IP}/kns
Bye.
References
- Proxmox – Network model:
http://pve.proxmox.com/wiki/Network_Model
Some days ago I saw a post on the LinkedIn’s Alfresco forums asking ‘Which front end framework is Generally used with Alfresco?’, for this reason I started to research and test them and discovered with joy that the trend is to use lightweight frameworks capable of creating rich interfaces quickly. Well here I put the review: Because I started to carefully review and discovered with joy that the trend is to use lightweight frameworks capable of creating rich interfaces quickly. Well here I put the review:
I. What is a client for Alfresco ECM ?
A client for Alfresco is any webapp or desktop app that consumes the Alfresco’s services, this client app can be created with Alfresco’s standard framework or with third party frameworks.
Several endusers want always customize traditional and existing Alfresco’s web clients, because these do not fit its requeriments.
Then, they quickly seek to modify existing Alfresco’s webclient and if this is not possible, then seek a tool (framework) to build a desktop or client from scratch.
What are the main reasons why you need to modify Alfresco’s webclients or create new ones?
Well, there are several reasons:
- The technology stack in the company is not Java.
- Is very difficult to make changes. Although there is much online information available on how to make customizations to Alfresco Explorer and Alfresco Share.
- Make changes in existing webapp are not supported.
- UI (look&feel) is not aligned to corporate graphical style.
- Alfresco’s content must be delivered for any devices: iPad, Android tablet, PC, etc.
- … or simply, everybody has different requirements.
Well, this post will review existing initiatives, RIA, RDA (Rich Desktop App) and RAD frameworks for developing clients for Alfresco ECM.
II. List of Clients
1. Alfresco Explorer
Alfresco Explorer is the clasic webapp bundled with Alfresco ECM, It is the principal web application to do document management, this offers some functionalities of system administratios.
Big changes or personalizations on this webapp must be done by XML file (Spring) configuring.
* Web: http://www.alfresco.com
* License: Enterprise Edition is open source with commercial support, Community Edition is LGPL 2 with some exception.
* Technology:
Alfresco Explorer based in JavaServerFace.
2. Alfresco Share
* Provides a rich web-based collaboration environment for managing documents, wiki content, blogs and more.
* Is based on Alfresco Surf API (now is a Spring project).
* Web: http://www.alfresco.com
* License: Idem to Alfresco Explorer
* Technology:
Alfresco Share based in SpringSurf/Webscripts.
3. Opsoro
“opsoro is an alternative web client for the Alfresco Enterprise Content Management Plattform. It’s goal is to provide an easier user interface with a richer user experience by leveraging the latest web technologies.”
* Version: ExtJS-version is 0.1beta
* Web: http://www.opsoro.org
* License: GPL
* Architecture: http://www.opsoro.org/architecture
* Technology:
- Alfresco server side: Opsoro does uses standard Alfresco Web Scripts.
- Web server side: Ext JS 2.0
* Features:
Basic document management features as:
- Folder, category and tag cloud browser
- My Alfresco portal with draggable portlets
- Document tagging
- Embedded preview (crop content & image preview)
- Inline view (supports text, pdf and images)
4. FlexSpaces (in browser, portlet and Air)
“Flex RIA client for Alfresco ECM”
* Version: build 04052011 from 2011/05/10
* Web: http://code.google.com/p/flexspaces
* License: GNU Lesser GPL
* Architecture: see my diagram above
* Technology: Flex, own RESTful WebScripts, Air.
* Features:
- Supports document management, search, workflow and wcm.
5. CMISSpaces (in browser, portlet and Air)
· “Flex RIA client for CMIS content management APIs.”
· Based on FlexSpaces
* Version: Build 18 from 2011/05/23
* Web: http://code.google.com/p/cmisspaces
* License: GNU Lesser GPL
* Architecture: see my diagram above
* Technology: Flex, BlazeDS, CMIS, Air.
* Features:
- Doc management, except:
· cut,copy,paste, advanced search not implemented, properties is read-only
- No workflow actions.
6. ifresco
“OpenSource Client for Alfresco
With the ifresco client we offer a powerful OpenSource Web-Client for Alfresco which has all features which are important and neccessary for the daily work with the DMS/ECM system and which can be operated easily and intuitiv.
ifresco is Web-browser based – but offers consumer-like experience of MS-Windows applications with sortable lists, context menus, drag and drop.
A plug-in interface allows to add new functions and features to the client without changing the base product.”
* Version: 0.2 beta from 2011/05
* Web: http://code.google.com/p/ifresco-client
* License: GNU GPL v3
* Architecture: http://www.ifresco.at/de/products/client/overview.html
* Technology:
* PHP5+
* Symfony 1.4 for MVC Framework
* Doctrine for database ORM
* Alfresco Integration based on Standard Restful Services & Webservice API
* No additional webscripts must be installed on the server!
* Server Side Converter for OFFICE2SWF Conversion (jodconvert & swftools)
* MySQL to save – administrative data, user sessions and favorites
* jQuery for various JavaScript functions and drag & drop
* ExtJS for the user interface with plug-ins
* Features:
* All the DMS/ECM functionalities.
* A plug-in interface allows to add new functions and features to the client without changing the base product.
* No workflow actions.
* Provides a mature and complete PHP Lib based on Alfresco PHP API (http://code.google.com/p/ifresco-php-library).
7. Liferay Document Library by CMIS
* Web: http://www.liferay.com
* License: GNU General Public License version 3.0 (GPLv3) for Community Edition
* Architecture: see my diagram above
* Technology:
Up to version 6.0.6 was possible to use Liferay Document Library to connect to any CMIS repository through a Liferay Hook, but was little usable in real scenarios, now in version 6.1b3 we can connect to any CMIS repository and allow synchronization between Alfresco repository and Liferay.
I think this is a huge step forward demonstrating the strength of CMIS interface to any type of application in front-end side.
* Features:
- Connect to any CMIS repository
- Still remaining to be developed all the features of CMIS 1.0
- It is very usable in real scenarios.
8. DoCASU
“The goal of DoCASU is to provide to the Alfresco Community a Custom Alfresco UI with a strong focus on User eXperience. This will be less confusing for average end users and will permit a broader acceptance of the solution by a larger group of users.”
* Version: 1.6.3 from 2010/01/08
* Web: http://docasu.sourceforge.net
* License: GNU GPL
* Architecture: http://docasu.sourceforge.net/productInfo.html
* Technology: ExtJS, own WebScripts (REST) and WS.
* Features:
DoCASU provides the functionality that average end users need to easily work with Alfresco:
- Folder Actions (View, create, delete, rename Folder, Create HTML or Text File, Upload File, Paste all)
- File Actions (View, update, delete, checkout, checkin, copy File, Download File, Add to favorites, Mail Link to File, Copy File Path/URL to clipboard)
- Simple and Advanced Search (Node type, Creation date, Modification date, Look in current folder, all folders)
- No workflow actions
9. ExtAlf
“This is not an Opsoro or FlexSpaces alternative, rather than a developer toolkit or a simple SDK what supports embedding Alfresco backend functionality into Web2.0/AJAX portals and frontends.”
* Web: http://louise.hu/poet/?p=753
* License: ExtAlf is part of a bigger project what is closed-source yet.
* Architecture: see diagram above
* Technology: ExtJS and own WebScripts
* Features:
- Doc management.
- More info here: http://louise.hu/poet/?p=927
10. CMIS Explorer
http://blogs.citytechinc.com/sjohnson/?p=60
http://code.google.com/p/cmis-explorer
11. Alfresco Office Plugin
“Implemented on a mini-browser windows, all actions available through REST API (HTML response for UI, others JSON for responses to update UI and data retrieval”.
Core services accessible through plugin:
- Document management
- Workflow
- Search
12. SCAr
http://wiki.rivetlogic.org/display/SCAr/Home
13. AWPr
“AWPr (Alfresco Web Script Portlet rivet) is a JSR-286 portlet that can be used to expose remote Alfresco Web scripts, including those that need user authentication.”
* Web: http://wiki.rivetlogic.org/display/AWPr/About+AWPr
* License: GNU Affero General Public License.
* Version:
14. Alfresco Web Script Portlet
“A webscript portlet for Liferay Portal, supporting multiple modes of authentication, a simple AJAX proxy and jQuery support.”
* Web: http://forge.alfresco.com/projects/liferaywsp
* License: MIT/X Consortium License
* Version: 1.0 of May/31/2010
15. WeWeBu OpenWorkdesk
“WeWebU OpenWorkdesk is an application suite (not just a CMIS browser!) for Enterprise Content Management (ECM) with an intuitive Web 2.0 front-end.”
* Web: http://openworkdesk.org (http://sourceforge.net/projects/owd)
* License: GNU General Public License version 3.0 (GPLv3) for Community Edition
* Version: 3.2.0.0 sprint6
* Architecture:
Integration using CMIS standard and custom framework (WeWebU OpenECM-Framework) more info here:
http://www.wewebu.de/fileadmin/user_upload/software/OECM_Architektur_EN.gif
* Technology:
-Java, CMIS and ExtJS 3.2.0 for UI in frontend
* Features:
The Community Edition version contains standard functionalities related to document manangement and supports all CMIS-enabled ECM systems:
- checkin, checkout, create, delete, search, …
Extra functionalities as workflow interactions, etc. are not availables in Community Edition.
For more detailed information about editions, here is a short comparison matrix:
http://www.openworkdesk.org/system/files/u4/20100623_OS-Editionen-Matrix_All.jpg
For an updated roadmap, you can see here:
http://www.openworkdesk.org/roadmap
III. Meta-frameworks
1. Jibe Framework (AlfExt)
http://code.google.com/p/jibeframework
2. Spring Surf
http://www.springsurf.org
3. Apache Chemistry (CMIS)
http://chemistry.apache.org
4. Spring Surf CMIS Application Browser
“Spring Surf provides a scriptable approach to building web applications. OpenCMIS provides a Java client library for accessing any CMIS compliant content repository. By combining the two, we create a development platform for building CMIS enabled web applications.”
http://blogs.alfresco.com/wp/cmis/2010/03/17/spring-surf-and-opencmis-integration
http://blogs.alfresco.com/wp/cmis/2010/06/14/spring-surf-and-opencmis-integration-part-2
5. Struts2 CMIS Explorer
“Struts2CmisExplorer is a web-based CMIS explorer. It uses Struts2 for the user interface.
If you have documents stored in your ECM repository and want to expose them (or some of them) to your clients/employees through an Intranet (or Internet/portal) web application…”
http://code.google.com/p/struts2cmisexplorer
6. Drupal + CMIS
http://drupal.org/project/cmis
7. Joomla + CMIS
http://blog.joomlatools.eu/2008/12/joomla-meet-alfresco.html
8. Drupal Open Atrium + CMIS
http://ecmarchitect.com/archives/2010/03/22/1141
9. ifresco PHP Lib
“ifresco PHP Library extends the Alfresco PHP Library, many RESTFul Services (which are used by Share) are implemented. Zoho Upload is implemented in here too.”
* Web: http://code.google.com/p/ifresco-php-library
* License: GNU GPL v3
* Technology:
- PHP5+
- Alfresco Integration based on Standard Restful Services & Webservice API
- No additional webscripts must be installed on the server!
- Parts of the Administration Service
- Category Management
- Lucene Search for Limited Result Query’s
IV. Conclusions
- This review concludes that the trend is to use existing products (ifresco, Drupal, OpenAtrium, Liferay, ….) enabling rapid integration with Alfresco services.
- The second option is to create RIA applications from scratch, and quickly, taking advantage of existing metaframeworks, we can see in doCASU, ExtAlf, AWPr, FlexSpace, etc.., The fact that they have started as a proof of concept and then have become standalone products confirms this trend.
- You can download a resume table with all features of each product reviewed from here.
I think that we are reaching the maturity level in Liferay and Alfresco, because we can create applications on top of them of fastly and easy way.
Alfresco ECM has functionalities exposed as a RESTful API, as know as Alfresco Webscripts, built on the basis of Spring Surf.
Liferay Portal has Liferay IDE based on Eclipse where we can create from scratch different types of Portlets. Also Liferay allows to include external libraries as jQuery, ExtJS, Vaadin, etc. that allows to develop highly customized portlets.
Right now, when several people ask me how to integrate Alfresco into Liferay, after I ask them what does mean when you said *integrate*?. Well I say that implies several thing as:
Integration mean:
- User and roles, SSO ?
- Include Alfresco Explorer or Share as a Portlet?
- Include Alfresco Explorer inside iFrame Portlet?
- Call any Alfresco’s functionality from a Portlet?
- …
Well, everything is possible to do, but to create applications from scratch following point 5 was very difficult, but now I think is the quickest way to do it, also the best from an architectural point of view.
This post explain how to do a portlet calling to Alfresco’s Webscripts (REST URIs) via ajax using jQuery. I also give some recommendations.
Requeriments
- Liferay IDE version 1.3.1 as IDE
- Liferay Portal version 6.0.6 installed into IDE
- Liferay SDK version 6.0.6 installed into IDE
- Alfresco ECM version 3.4d CE installed
- Identify and verify Alfresco Webscripts:
- Login and get Ticket: http://${ALFRESCO}/alfresco/service/api/login?u=${USR}&pw=${PWD}
- Folder browser: http://${ALFRESCO}/alfresco/service/sample/folder${INITIAL_FOLDER}
- jQuery version 1.6.3 added to new portlet
Process
1. From Liferay IDE create a new Liferay Project that implement GenericPortlet as follow:
2. The structure of Project in Liferay IDE will be as follow:
3. Add code in view.jsp to call serverResource method and to do ajax call to Alfresco. Also, in view.jsp you will add JavaScript code (jQuery) for parsing HTML/XML ajax responses.
<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
<portlet:defineObjects />
This is the <b>Ajax Alfresco Folder Browser</b> portlet in View mode.
<hr/>
<%
// "http://192.168.56.101:8080";
String strUrlAlfIP = renderRequest.getAttribute("alfServer").toString();
// "/alfresco/service/api/login?u=admin&pw=admin";
String strUrlAlfLogin = renderRequest.getAttribute("alfTicketSvc").toString() + "?" + renderRequest.getAttribute("alfTicketSvcParams");
// "/alfresco/service/sample/folder/Company%20Home";
String strUrlAlfDir = renderRequest.getAttribute("alfWebscriptBrowserURL").toString();
%>
<portlet:resourceURL var="resourceUrlAlfIP" id="<%=strUrlAlfIP%>" escapeXml="false" />
<portlet:resourceURL var="resource1AlfLogin" id="<%=strUrlAlfIP.concat(strUrlAlfLogin.trim()).trim()%>" escapeXml="false" />
<portlet:resourceURL var="resource2AlfFolderBrowser" id="<%=strUrlAlfIP.concat(strUrlAlfDir.trim()).trim()%>" escapeXml="false" />
<script type="text/javascript">
jQuery(document).ready(function() {
var urlAlfIP = "<%=strUrlAlfIP%>";
var currentAlfTicket = jQuery("#<portlet:namespace/>alfrescoticket").text();
$("#<portlet:namespace/>buttonAlfLoginAndTicket").click(function(){
if (currentAlfTicket == "") {
jQuery("#<portlet:namespace/>loading").html("<img src='<%=request.getContextPath()%>/images/2-1.gif' border='0'> loading ...");
jQuery("#<portlet:namespace/>errormsg").html("");
jQuery.get( '<%=renderResponse.encodeURL(resource1AlfLogin)%>',
function (data1, textStatus1, jqXHR1) {
jQuery("#<portlet:namespace/>alfrescoticket").html(data1.getElementsByTagName("ticket")[0].childNodes[0].nodeValue);
jQuery.get( '<%=renderResponse.encodeURL(resource2AlfFolderBrowser)%>',
'alf_ticket=' + data1.getElementsByTagName("ticket")[0].childNodes[0].nodeValue,
function (data2, textStatus2, jqXHR2) {
jQuery("#<portlet:namespace/>loading").html("");
jQuery("#<portlet:namespace/>alfrescowscontent").html("<b><font color='blue'>Folder:</font></b> " + $(data2).filter("title").text() + "<br><table>");
var i=1;
$(data2).find("a").each(
function() {
$("#<portlet:namespace/>alfrescowscontent").append( "<tr><td>" + i++ + " > </td><td><a href='" + $(this).attr("href") + "' id='IdLinkAlfPath'>" + $(this).text() + "</a></td></tr>");
}
);
jQuery("#<portlet:namespace/>alfrescowscontent").append("</table><hr/>");
jQuery("#<portlet:namespace/>errormsg").append("<font color='green'>* textStatus2: " + textStatus2 + "</font><br/>");
jQuery("#<portlet:namespace/>errormsg").append("<font color='green'>* jqXHR2: " + jqXHR2.status + "</font><br/>");
jQuery("#<portlet:namespace/>loading").html("");
},
'html'
).error(function() { //alert("2nd ajax error");
}); // 2nd end-jquery-get
jQuery("#<portlet:namespace/>errormsg").append("<font color='green'>* textStatus1: " + textStatus1 + "</font><br/>");
jQuery("#<portlet:namespace/>errormsg").append("<font color='green'>* jqXHR1: " + jqXHR1.status + "</font><br/>");
} // end-function-data
).error(function() { //alert("1st ajax error");
}); // 1st end-jquery-get
} // end-if
}); // end-click-button
$('a#IdLinkAlfPath').live('click', function(event) {
jQuery("#<portlet:namespace/>loading").html("<img src='<%=request.getContextPath()%>/images/2-1.gif' border='0'> loading ...");
var urlAlfGeneric = "" + "<%=renderResponse.encodeURL(resourceUrlAlfIP)%>";
urlAlfGeneric = urlAlfGeneric.replace(encodeURIComponent(urlAlfIP), encodeURIComponent(urlAlfIP + $(this).attr("href")));
jQuery.get( urlAlfGeneric,
'alf_ticket=' + jQuery("#<portlet:namespace/>alfrescoticket").text(),
function (data3, textStatus3, jqXHR3) {
jQuery("#<portlet:namespace/>loading").html("");
jQuery("#<portlet:namespace/>alfrescowscontent").html("<b><font color='blue'>Folder:</font></b> " + $(data3).filter("title").text() + "<br><table>");
var i=1;
$(data3).find("a").each( function() {
$("#<portlet:namespace/>alfrescowscontent").append( "<tr><td>" + i++ + " > </td><td><a href='" + $(this).attr("href") + "' id='IdLinkAlfPath'>" + $(this).text() + "</a></td></tr>");
});
jQuery("<portlet:namespace/>alfrescowscontent").append("</table>");
jQuery("#<portlet:namespace/>errormsg").append("<font color='green'>* textStatus3: " + textStatus3 + "</font><br/>");
jQuery("#<portlet:namespace/>errormsg").append("<font color='green'>* jqXHR3: " + jqXHR3.status + "</font><br/>");
jQuery("#<portlet:namespace/>loading").html("");
},
'html'
).error(function() { //alert("3rd ajax error");
}); // 3rd end jQuery.get
return false; // works, does not propagate
});
$('a#IdLinkAlfPath').trigger('click');
// jquery error management
jQuery("#<portlet:namespace/>errormsg").ajaxError(
function (event, jqXHR, ajaxSettings, thrownError) {
jQuery("#<portlet:namespace/>errormsg").html("");
jQuery("#<portlet:namespace/>errormsg").append("<font color='red'>* Status Code jqXHR: " + jqXHR.status + "</font><br/>");
jQuery("#<portlet:namespace/>errormsg").append("<font color='red'>* Status Text jqXHR: " + jqXHR.statusText + "</font><br/>");
jQuery("#<portlet:namespace/>errormsg").append("<font color='red'>* URL: " + ajaxSettings.url + "</font><br/>");
jQuery("#<portlet:namespace/>errormsg").append("<font color='red'>* thrownError: " + jqXHR.statusText + "</font><br/>");
// intix: does not work HTTP_STATUS_CODE in 6.0.6 CE
// http://issues.liferay.com/browse/LPS-13039
// for this reason, bellow messages will not be show
if(jqXHR.status == 0) {
// a status of 0 indicates a failure to connect to alfresco
jQuery("#<portlet:namespace/>errormsg").append("<font color='red'>* Message: Unable to reach the Alfresco server, check your network connection</font>");
}else if(jqXHR.status == 403) {
// a 403 indicates that the login via the alfresco ticket service has failed.
// display the "access denied" div
jQuery("#<portlet:namespace/>errormsg").append("<font color='red'>* Message: An authentication error has occurred loading content from Alfresco, check login params</font>");
}else if(jqXHR.status == 500) {
// we shouldn't see many 500 errors from Alfrsco services if they
// have been properly configured.
jQuery("#<portlet:namespace/>errormsg").append("<font color='red'>* Message: A server error has occurred loading content from Alfresco</font>");
}else {
// report timeouts to the user
jQuery("#<portlet:namespace/>errormsg").append("<font color='red'>* Message: Request to Alfresco server has timed out</font>");
}
jQuery("#<portlet:namespace/>loading").html("");
}
); //end-ajax-error
// toggles the slickbox on clicking the noted link
$('#alf-error-slick-toggle').click(function() {
$('#<portlet:namespace/>errormsg').toggle(400);
return false;
});
// toggles the slickbox on clicking the noted link
$('#alf-content-slick-toggle').click(function() {
$('#<portlet:namespace/>alfrescowscontent').toggle(400);
return false;
});
});
</script>
<input type="button" id="<portlet:namespace/>buttonAlfLoginAndTicket" value="Login Alfresco and get Ticket">
<hr>
<!-- div to contain ticket retrieved from Alfresco Login web script -->
<div id="<portlet:namespace/>alfrescoticket"></div>
<!-- Div to hold loading image -->
<div id="<portlet:namespace/>loading"><img src="<%=request.getContextPath()%>/images/2-1.gif" border="0"> ...click on above button to start or change params in portlet menu preferences!</div>
<br/>
<!-- Div to hold error messages -->
<a href="#" id="alf-error-slick-toggle">[+] Toggle error console</a>
<div id="<portlet:namespace/>errormsg" class="div_bg_white" > :) </div>
<!-- Div to hold logs -->
<div id="<portlet:namespace/>logs"></div>
<br/>
<!-- Div to hold alfresco content -->
<a href="#" id="alf-content-slick-toggle">[+] Toggle Alfresco content</a>
<div class="div_bg_white" id="<portlet:namespace/>alfrescowscontent">:)</div>
4. AjaxAlfrescoFolderBrowser.java extends GenericPortlet, in the serverResource method manages ajax calls and returns ResourceResponse to be parsed in view.jsp
package info.intix.lfry.samples;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.GenericPortlet;
import javax.portlet.PortletException;
import javax.portlet.PortletMode;
import javax.portlet.PortletPreferences;
import javax.portlet.PortletRequestDispatcher;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;
/**
* Portlet implementation class AjaxAlfrescoFolderBrowser
*/
public class AjaxAlfrescoFolderBrowser extends GenericPortlet {
public void init() {
editJSP = getInitParameter("edit-jsp");
helpJSP = getInitParameter("help-jsp");
viewJSP = getInitParameter("view-jsp");
}
/**
* intix: Changes are persisted when the store method is called.
* The store method can only be invoked within the scope of a processAction call.
* Changes that are not persisted are discarded when the processAction or render method ends.
*/
public void processAction(
ActionRequest actionRequest, ActionResponse actionResponse)
throws IOException, PortletException {
//super.processAction(actionRequest, actionResponse);
PortletPreferences prefs = actionRequest.getPreferences();
prefs.setValue("ticketUrl", actionRequest.getParameter("ticketUrl"));
prefs.setValue("alfServer", actionRequest.getParameter("alfServer"));
prefs.setValue("alfTicketSvc", actionRequest.getParameter("alfTicketSvc"));
prefs.setValue("alfTicketSvcParams", actionRequest.getParameter("alfTicketSvcParams"));
prefs.setValue("alfWebscriptBrowserURL", actionRequest.getParameter("alfWebscriptBrowserURL"));
prefs.setValue("alfWebscriptBrowserURLParams", actionRequest.getParameter("alfWebscriptBrowserURLParams"));
prefs.setValue("jQuery", actionRequest.getParameter("jQuery"));
prefs.store();
actionResponse.setPortletMode(PortletMode.EDIT);
}
/**
* intix:
*/
public void doEdit(
RenderRequest renderRequest, RenderResponse renderResponse)
throws IOException, PortletException {
if (renderRequest.getPreferences() == null) {
//super.doEdit(renderRequest, renderResponse);
} else {
// get editable preferences
PortletPreferences prefs = renderRequest.getPreferences();
// intix: these values will override options in portlet.xml
renderRequest.setAttribute("alfServer", (prefs.getValue("alfServer", "")));
renderRequest.setAttribute("alfTicketSvc", (prefs.getValue("alfTicketSvc", "")));
renderRequest.setAttribute("alfTicketSvcParams", (prefs.getValue("alfTicketSvcParams", "")));
renderRequest.setAttribute("alfWebscriptBrowserURL", (prefs.getValue("alfWebscriptBrowserURL", "")));
renderRequest.setAttribute("alfWebscriptBrowserURLParams", (prefs.getValue("alfWebscriptBrowserURLParams", "")));
renderRequest.setAttribute("jQuery", (prefs.getValue("jQuery", "")));
include(editJSP, renderRequest, renderResponse);
}
}
public void doHelp(
RenderRequest renderRequest, RenderResponse renderResponse)
throws IOException, PortletException {
include(helpJSP, renderRequest, renderResponse);
}
/**
* intix:
*/
public void doView(
RenderRequest renderRequest, RenderResponse renderResponse)
throws IOException, PortletException {
try {
// get portlet prefs
PortletPreferences prefs = renderRequest.getPreferences();
String alfServer = prefs.getValue("alfServer", "");
String alfTicketSvc = prefs.getValue("alfTicketSvc", "");
String alfTicketSvcParams = prefs.getValue("alfTicketSvcParams", "");
String alfWebscriptBrowserURL= prefs.getValue("alfWebscriptBrowserURL", "");
String alfWebscriptBrowserURLParams = prefs.getValue("alfWebscriptBrowserURLParams", "");
String jQuery = prefs.getValue("jQuery", "");
String ticketUrl = alfServer + alfTicketSvc + "?" + alfTicketSvcParams;
renderRequest.setAttribute("ticketUrl", ticketUrl);
renderRequest.setAttribute("alfServer", alfServer);
renderRequest.setAttribute("alfTicketSvc", alfTicketSvc);
renderRequest.setAttribute("alfTicketSvcParams", alfTicketSvcParams);
renderRequest.setAttribute("alfWebscriptBrowserURL", alfWebscriptBrowserURL);
renderRequest.setAttribute("alfWebscriptBrowserURLParams", alfWebscriptBrowserURLParams);
renderRequest.setAttribute("jQuery", jQuery);
}catch(Exception ex) {
_log.error(ex);
}
include(viewJSP, renderRequest, renderResponse);
}
protected void include(
String path, RenderRequest renderRequest,
RenderResponse renderResponse)
throws IOException, PortletException {
PortletRequestDispatcher portletRequestDispatcher =
getPortletContext().getRequestDispatcher(path);
if (portletRequestDispatcher == null) {
_log.error(path + " is not a valid include");
}
else {
portletRequestDispatcher.include(renderRequest, renderResponse);
}
}
/**
* intix: serveResource does HTTP and Ajax call behind of Liferay
*/
public void serveResource(ResourceRequest request, ResourceResponse response) throws PortletException, IOException {
response.setContentType("text/xml");
String strAlfTicket= request.getParameter("alf_ticket");
String strQueryString = "";
if (strAlfTicket != null) {
// intix: if alf_ticket exists, then user was authenticate with alfresco
Map<String, String[]> mapParameters = request.getParameterMap();
for (Entry<String, String[]> entryParameter : mapParameters.entrySet()) {
System.out.println(">> Key = " + entryParameter.getKey() + ", Value = " + entryParameter.getValue()[0]);
strQueryString = strQueryString + entryParameter.getKey() + "=" + entryParameter.getValue()[0] + "&";
}
} else {
// intix: ticket is null
String strUser = request.getParameter("u");
String strPw = request.getParameter("pw");
strQueryString = "u=" + strUser + "&pw=" + strPw;
}
String requestUrl = request.getResourceID();
BufferedInputStream web2ProxyBuffer = null;
BufferedOutputStream proxy2ClientBuffer = null;
HttpURLConnection con;
URL url = null;
try {
int oneByte = 0;
String methodName;
if (strAlfTicket != null) {
url = new URL(requestUrl + "?" + strQueryString);
} else {
url = new URL(requestUrl);
}
con = (HttpURLConnection) url.openConnection();
methodName = request.getMethod();
System.out.println(">> methodName: " + methodName);
con.setRequestMethod(methodName);
con.setDoOutput(true);
con.setDoInput(true);
con.setFollowRedirects(false);
con.setUseCaches(true);
con.connect();
// does not work in 6.0.6 CE
// http://issues.liferay.com/browse/LPS-13039
int httpRespCode = con.getResponseCode();
response.setProperty(ResourceResponse.HTTP_STATUS_CODE, Integer.toString(httpRespCode));
System.out.println(">> HTTP_STATUS_CODE: " + httpRespCode);
if(methodName.equals("POST")) {
BufferedInputStream clientToProxyBuf = new BufferedInputStream(request.getPortletInputStream());
BufferedOutputStream proxyToWebBuf = new BufferedOutputStream(con.getOutputStream());
while ((oneByte = clientToProxyBuf.read()) != -1) {
proxyToWebBuf.write(oneByte);
}
proxyToWebBuf.flush();
proxyToWebBuf.close();
clientToProxyBuf.close();
}
for( Iterator i = con.getHeaderFields().entrySet().iterator() ; i.hasNext() ;) {
Map.Entry mapEntry = (Map.Entry)i.next();
if(mapEntry.getKey()!=null) {
//response.setHeader(mapEntry.getKey().toString(), ((List)mapEntry.getValue()).get(0).toString());
System.out.println(">> HEADER > " + mapEntry.getKey().toString() + "\t" + ((List)mapEntry.getValue()).get(0).toString());
}
}
InputStream in = con.getInputStream();
web2ProxyBuffer = new BufferedInputStream(in);
proxy2ClientBuffer = new BufferedOutputStream(response.getPortletOutputStream());
byte [] byteArray = new byte[1024]; // intix: any array size is valid
int intByteRead = web2ProxyBuffer.read(byteArray);
while (intByteRead > 0) {
// intix: print response-html/xml, must be the first line after while loop
System.out.println(new String(byteArray, 0, intByteRead));
proxy2ClientBuffer.write(byteArray, 0, intByteRead);
intByteRead = web2ProxyBuffer.read(byteArray);
}
proxy2ClientBuffer.flush();
proxy2ClientBuffer.close();
web2ProxyBuffer.close();
con.disconnect();
} catch(Exception e) {
e.getMessage();
} finally {
//
}
}
protected String editJSP;
protected String helpJSP;
protected String viewJSP;
private static Log _log = LogFactoryUtil.getLog(AjaxAlfrescoFolderBrowser.class);
}
5. When you have successfully deployed the portlet, open a browser, login, then add the new portlet to any page. Then you see the following:
Conclussions
- In the JSR-286 specifications (Portlet 2.0) now is possible to use serveResource() method andto request data. I use it as a servlet-proxy to do ajax calls to Alfresco.
- Exists a issue in Liferay 6.0.6 when setting ResourceResponse.HTTP_STATUS_CODE in the Portlet response (http://issues.liferay.com/browse/LPS-13039), this implies I have to manage HTTP_STATUS_CODE by parsing the Ajax HTML/XML responses.
- I have Liferay and Alfresco in different VMs (different IP and Ports) and I never had cross-domain issues thanks to Point #1 (serveResource nad portlet:resourceURL), but if you run into it is recommended that you use Apache HTTP server as a reverse-proxy.
You can download entire project (source code) and compiled from here:
- Source code (Liferay IDE project): AjaxAlfrescoFolderBrowser-portlet.zip
- Compiled: AjaxAlfrescoFolderBrowser-portlet.war
End.
Remote debugging of Liferay portlets
2011/09/09
Debugging is a task very important when building software, this allows software development with high level of quality (without bugs) because “debugging” enable you repeat cycles of “to do and to test” several time.
When developing Liferay portlets, Liferay Portal server will contain the portlets in a PC different of the PC of developer.
For this reason, debugging is an important task when working in distributed project teams with a single and/or centralized development server.
Then, remote debugging means you could debug an application or portlet on server from a different computer.
This post discusses how to use the Eclipse IDE for remote debugging on Liferay.
Versions used
- Liferay Portal bundled with Tomcat: liferay-portal-tomcat-6.0.6-20110225.zip
- Liferay IDE 1.2
Remote Debugging configuration
1. In your Liferay server side, if you have installed Tomcat bundle, to add this line into $TOMCAT_HOME/bin/setenv.bat or setenv.sh before you set any JAVA_OPTS:
In windows:
set JAVA_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n
In Mac OSX the file will be as follow:
## intix - remote debugging JAVA_OPTS="-Xdebug -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n" JAVA_OPTS="$JAVA_OPTS -Dfile.encoding=UTF8 -Duser.timezone=GMT -Xmx1024m -XX:MaxPermSize=256m"
2. Restart Tomcat server. You should see in log (catalina.out) a message showing that port 8000 is opened and ready to use.
[...] Listening for transport dt_socket at address: 8000 Sep 8, 2011 9:55:02 PM org.apache.catalina.core.AprLifecycleListener init INFO: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: .:/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java Sep 8, 2011 9:55:02 PM org.apache.coyote.http11.Http11Protocol init INFO: Initializing Coyote HTTP/1.1 on http-8080 Sep 8, 2011 9:55:02 PM org.apache.catalina.startup.Catalina load INFO: Initialization processed in 456 ms [...]
Note:
* If you have Liferay Portal configured as server into your Liferay IDE, do not launch Tomcat from this IDE. It is possible that remote debugging port is not opened.
* For a successfully debugging, run Tomcat from a shell as follow:
chilcano$ sh ./startup.sh ; tail -f ../logs/catalina.out
3. In your PC of development, to open Eclipse, Liferay IDE or Liferay Studio, in top menu to do click on “Run > Debug Configurations…”, will appear a dialog setup window where you have to create a new “Remote Java Application”.
Follow the image bellow:
4. Under “Remote Java Application” to add a entry, add values of hostname and port of remote server.
Follow the image bellow:
5. In “Debug Configurations…” dialog window, click “Source” and to add source code of your project to be debugged. At end, start debugging by click on “Debug” button.
Your IDE will ask you if you want to change to “Debug perspective”. You accept it.
6. In your IDE, put some “breakpoints” on your code.
7. Open your browser and go to your webapp’s URL, if you put breakpoints are in appropriate places, then Eclipse will show the line of code being executed.
You have nice debug on Liferay!.
Bye.
References:
1. Introduction
When working a Liferay Portal in Organizations with existing web applications, generally new web applications will need to be integrated in current Authentication and Web-SSO service.
This document explains how to create new java web applications knowing that they will use the AuthN service and will Web-SSO with Liferay.
Although, this document is for new java web applications, existing web applications (based in java, php,. net, ruby, …) can also use it as this document explains the most important steps to perform.
This document can be taken as a set of best practices (including source code) when you want to integrate with CAS.
Note:
- This document does not say how to do Single-Sign Out or logout, only Single-Sign On or login.
2. Use cases when CAS-ifying web applications
Use case #1: Authentication
Use case #2: Web-SSO
To perform Web-SSO, we will need 2 webapps, the first one is Liferay, and the second one is webappA. Both should be authenticated with CAS-server.
The main difference between authentication and web-sso processes is that CAS shares authenticated session through CAS Service Manager.
Use case #3: Web Single Sign Off or Single Log Out
Single Sign Out or Single Log Out means that CAS-server contacts each webapp and notifies them that you have logged out. Then you should invalidate or delete all cookies stored in your web browser.
This protocol is implemented in Java CAS client library only.
Use case #4: Logout
To perform a logout means (involves) to close authenticated session in CAS-server side. Afterwards, you will need to make sure that the cookie does not exist in your web browser.
3. Process of installation and deployment of a CAS-ified webapp
When you install and deploy any web application in an environment where Web-SSO is enabled, you should to following steps.
Generally, the steps 1, 2 and 3 have already been made and it is only pending to how to configure CAS-client, CAS-service manager, java webapp, etc.
CAS service manager
It is necessary to define an URL for identify the new web application. This URL will be called the “URL Service”:
- Identify the CAS-ified webapp trying to authenticate in CAS-server. In almost all cases, this will be the URL of the web application.
- In a successfully login process is used to redirect web browser to URL specified.
- It is used as filter for CAS Services Management in Web-SSO process allowing to do SSO between webapps registered.
To replace the URL/IP for yours.
Develop your Java Webapp and configure Tomcat
Firstly, you have to design your scenario to do Web-SSO. In this case, We have 3 servers:
- lfry01 or svdapp85 (IP 192.168.56.101, HTTP port 6060): Liferay Portal
- lfry02 (IP 192.168.56.102 or IP 10.16.111.135, HTTP port 8080): Tomcat server hosting new CAS-ified Java Web App
- blcr00 or svdapp85 (IP 192.168.56.103, SSL port 6443): Tomcat server hosting CAS server and CAS service manager
Our scenario will look like to following diagram.
1. Install Tomcat, enable SSL (lfry02) using server.xml sample:
<?xml version='1.0' encoding='utf-8'?>
<Server port="8005" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<Listener className="org.apache.catalina.core.JasperListener" />
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<GlobalNamingResources>
<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />
</GlobalNamingResources>
<Service name="Catalina">
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<Connector protocol="org.apache.coyote.http11.Http11NioProtocol"
port="8443" maxHttpHeaderSize="8192" SSLEnabled="true"
maxThreads="150"
enableLookups="false" disableUploadTimeout="true"
acceptCount="100" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS"
keystoreFile="D:\devel\usr-dev\apache-tomcat-6.0.29\webapps\mywebappssotest1.jks"
keystorePass="changeit"
truststoreFile="D:\devel\usr-dev\jdk_6u21\Java\lib\security\cacerts" />
<!-- My CAS URL service = https://localhost:8443/webssotest1/protected/ -->
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
<Engine name="Catalina" defaultHost="localhost">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true"
xmlValidation="false" xmlNamespaceAware="false">
</Host>
</Engine>
</Service>
</Server>
2. Generate key pair and export certificate SSL of this Tomcat (lfry02).
3. Install CAS root certificate (blcr00) as trusted cert into JVM cacert repository of Tomcat (lfry02).
4. Use this Java webapp (webssotest1.war), deploy this webapp into Java Web Server (lfry02).
5. Test this web application in HTTP and HTTPS mode.
Connect your Java Webapp to CAS
We have created a basic sample of java web application based in JSP (webssptest1.war). We recommend that you try to deploy and configure this web application before trying something more complex.
1. In blcr00 use existing standard model of authentication based on usr/pwd where both are equals. If Liferay has already used this model, this webapp should follow too.
2. In lfry02 (tomcat web.xml) configure CAS server, to use this sample file:
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="webssotest1"
version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>webssotest1</display-name>
<description>
WebSSO sample, how to use CAS Java Client 3.x.
In this sample exists a public area (/)
and a private area (/protected/*).
</description>
<filter>
<filter-name>CAS Authentication Filter</filter-name>
<filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
<init-param>
<param-name>casServerLoginUrl</param-name>
<param-value>https://svdapp85:6443/cas-server-webapp-3.3.5/login</param-value>
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>https://10.16.111.135:8443</param-value>
</init-param>
<init-param>
<param-name>renew</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>gateway</param-name>
<param-value>false</param-value>
</init-param>
</filter>
<filter>
<filter-name>CAS Validation Filter</filter-name>
<filter-class>org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter</filter-class>
<init-param>
<param-name>casServerUrlPrefix</param-name>
<param-value>https://svdapp85:6443/cas-server-webapp-3.3.5/</param-value>
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>https://10.16.111.135:8443</param-value>
</init-param>
<init-param>
<param-name>proxyCallbackUrl</param-name>
<param-value>https://svdapp85:6443/cas-server-webapp-3.3.5/proxyCallback</param-value>
</init-param>
<init-param>
<param-name>proxyReceptorUrl</param-name>
<param-value>/mywebappssotest1/proxyCallback</param-value>
</init-param>
</filter>
<filter>
<filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
<filter-class>org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>
</filter>
<filter>
<filter-name>CAS Assertion Thread Local Filter</filter-name>
<filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CAS Authentication Filter</filter-name>
<url-pattern>/protected/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CAS Validation Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CAS Assertion Thread Local Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CAS Validation Filter</filter-name>
<url-pattern>/proxyCallback</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
3. Make sure that exists CAS-client java libraries into WEB-INF/lib directory, as follow:
4. Test login and SSO with liferay.
Login to Liferay (lfry01), go to following URL, for example: http://svdapp85:6060/en/group/intix/home
You will be redirected to CAS login form, to entry an user/password valid in CAS-server.
Now, from same opened browser, switch to the CAS-ified webapp. Open following protected URL: http://10.16.111.135:8080/webssotest1/protected/
If all is OK, then you can see URL without user/pwd prompted.
The same applies if you do log into webssotest1.war first and then go to liferay.
The CAS login form is the first page displayed when trying to login from any application. This form is shared by any web application you want to do Web-SSO.
END.
Reference:
- JA-SIG Java Client Simple WebApp Sample
- Web-SSO between Liferay and Alfresco with CAS and Penrose part 1 and part 2
























