Wednesday, August 31, 2011

Button Action Not Firing in JSF Part II

Seems there's a lot of old problems resurfacing today.

As I went to test the navigation in my nifty new Messenger portlet I found the buttons doing absolutely nothing.  I was using static JSF navigation...  Nothing.  I tried a test action method and a test button... nothing.

The environment:

Windows 7
ICEFaces 1.8.1
Liferay 6
Tomcat 6

Guess what?

ICEFaces compresses its JavaScript resources when interacting with your browser.  Generally if users are expected to use Internet Explorer you have to configure your ICEFaces not to compress those resources because IE can't handle it.

Well it seems Chrome and Firefox can't handle it either these days, at least not in a Liferay 6 environment.

Add this to your web.xml:

<context-param>
<param-name>com.icesoft.faces.compressResources</param-name>
<param-value>false</param-value>
</context-param>

And all will be well.



SEVERE: Error listenerStart Part III

SEVERE: Context [/mybrokenportlet] startup failed due to previous errors


Now things are getting ridiculous...


Liferay 5.2 (Or Liferay 6... Doesn't matter)

So the gremlins came back on me with a vengeance when I started building a messenger portlet for Liferay. (Think of an internal E-mail system just within the portal. Nifty, huh? I'll put it up on Github when it's done.)


Again, using ICEFaces 1.8.1 and JSF 1.2 I went to deploy my test version of the portlet and *KABOOM* the above error.

So I checked to be sure all of my name references in my config files matched the name of the .war file. Oops! One didn't match... so I fixed that, undeployed the portlet, rebuilt and re-deployed it and...

*KABOOM*

So I went and checked that all of my class references were correctly capitalized in faces-config.xml and just for giggles redeployed it and *KABOOM*

So I went into my web.xml and commented out the listener tag to make it blow up on purpose and see what happened and...

I got a ClassNotFound error on my com.icesoft.faces.webapp.http.portlet.MainPortlet class.

AH-HAH!
Apparently when your .jars are missing Tomcat will throw an error a little different for the missing listener class than for the main servlet class, so beware.

What caused this?

As it turns out, Eclipse wasn't packaging my JSF and ICEFaces .jar files in the WEB-INF/lib folder when building the .war files. You see, I'd started this project on one machine, then moved it over to another and updated my build path references but NOT the Deployment Assembly. I don't know if it makes a difference that the project was first built on Eclipse Ganymede and now I'm working with Eclipse Helios, but either way here's how you fix it when Eclipse isn't including the .jar files you need in your output.

Right Click the project and select "Properties"
Click "Deployment Assembly"
You'll see a list of source items and the Deploy Path they'll be placed in. Make sure that all of your libraries and .jars are correct.

After correcting my .jar file paths, I was able to successfully deploy my project.

P.S. If I'd been building this thing with Maven, I wouldn't have had this trouble...

Still not working?  Go on to this post.






Monday, August 29, 2011

Projects on Github

So it was suggested in a comment on this post that I upload my code to Github.

So I checked that with my boss and he was cool with it so I created an account there and have uploaded the complete projects for the Shibboleth-Liferay-Hook and Shibboleth-Liferay-Extension to my new page here.

I thought about making these things buildable with Maven but frankly I think the best way to do it is using ant within the Liferay Plugins SDK. I do have other plugin projects that are Mavenized and will post them on Github at some point.

These projects are also available through the Liferay Community Downloads section of the Liferay website.

Enjoy!

Note: I'm not sure how much maintenance I will be doing to these projects. If I make any good changes to the projects here I'll update them on Github and, of course, if anyone finds problems and bugs with them we'll fix 'em, but mostly they're out there to help people figure this stuff out and learn.

Wednesday, August 24, 2011

Shibboleth and Liferay Part 6: The Finishing Touch

This is the bonus episode.

If you've gone through the last 5 posts and have a functioning Shibboleth-Liferay Web SSO setup then you're ready for this step.

You'll need to un-deploy the extension you deployed in the last post. Here's a page that has instructions on how to do so. It isn't like un-deploying portlets or hooks. Also, if you're un-deploying the extension in order to replace it with another, be sure to restart Liferay before attempting to install the replacement!

So at this point we have an Ext plugin that adds a new auto login module to the set already in Liferay. We have configured our portal-ext.properties to use it. All is well... until the IdP team decides to change the names of the attributes that pass the login data along. Now your code breaks because you have that value hard coded in your auto login class.

And as I've said before, nothing is worse than hard coded values. Nothing.

If you go into Liferay's Control panel and click "Portal Settings" from the menu at the left, and then choose "authentication" from the menu on the right, you will see a list of possible Web SSO providers to choose from, and you can choose whether each one is enabled or disabled. Wouldn't it be nice if Shibboleth were one of the options?

Well, it is on mine:



And now it can be on yours, too!

But first we need to revisit that Ext plugin we created in part 5.

You'll be adding two more classes which will be overriding existing classes in Liferay. Liferay stores settings for various elements of the portal in a value pair of classes called PropsKeys and PropsValues. We'll be overriding them both. The purpose of this is to make use of the "Enabled" and "User Header" settings when Shibboleth is selected from the Authentication menu, as pictured above.

"But wait!" You say. "My authentication module is already enabled! I've been using it! How can that be if I've never added this parameter before?"

The way the Liferay uses the auto login modules is by iterating through each of the modules you've enabled in your portal-ext.properties file if you've overridden that value, each time a user opens Liferay. If you look at some of the auto login classes already written in the Liferay source code, you'll notice that each class checks the value of its "Enabled" setting before doing anything else. In a sense, there's a sort of double layer of "on" switches for each of these auto login modules. Since the code we used in part 5 never checks the value of that setting, our module will always run when Liferay looks for it. We want our Shibboleth auto login module to work exactly like the built in modules so we want to match that feature.

In your Ext project, add a new set of folders under docroot/WEB-INF/ext-impl/src:
com/liferay/portal/kernel/util
And copy the PropsKeys.java class from the corresponding location in the Liferay source bundle into util.

What you'll see in this class is a VERY LONG list of public Strings being declared. Add these into it:

public static final String SHIBBOLETH_AUTH_ENABLED = "shibboleth.auth.enabled";
public static final String SHIBBOLETH_USER_HEADER = "shibboleth.user.header";
It doesn't matter where you put them, but since the variables are in alphabetical order I just kept to that approach.

Now you can save that class and add another folder set:

com/liferay/portal/util
also under /src.

From the corresponding folder in the source code, copy over the PropsValues.java file.
You'll see another long list of Strings, similar to PropsKeys. Add these lines:

public static final boolean SHIBBOLETH_AUTH_ENABLED = GetterUtil.getBoolean(PropsUtil.get(PropsKeys.SHIBBOLETH_AUTH_ENABLED));
public static final String SHIBBOLETH_USER_HEADER = PropsUtil.get(PropsKeys.SHIBBOLETH_USER_HEADER);
And save the file.

Now, we need to modify our ShibbolethAutoLogin.java file to make use of these parameters.

In the class variables section, add this line:

String userEmail = "";

We're making userEmail a class variable because we're going to need it inside try/catch blocks. Inside the login() method, under the line where you declared your String[] credentials, declare a new variable:

long companyId = PortalUtil.getCompanyId(req);
It's also a good idea to move the String[] credentials = null; line up to the top of the method now. Delete the old try{ and move it to the top of the method, right under the variable declaration.
The first thing we need to add inside our expanded try block is the check to see if the user has clicked the "Enabled" switch.

if (!PrefsPropsUtil.getBoolean(
companyId, PropsKeys.SHIBBOLETH_AUTH_ENABLED,
PropsValues.SHIBBOLETH_AUTH_ENABLED)) {

return credentials;
}

Note the use of the value pair coming from the two classes we modified earlier. Next, we set our userEmail variable to the value stored in Liferay's value pair:

userEmail = (String) req.getAttribute(PrefsPropsUtil.getString(companyId, PropsKeys.SHIBBOLETH_USER_HEADER,PropsValues.SHIBBOLETH_USER_HEADER));

The last change is a small one. Since we're always initializing userEmail when we declare it, in the if statement that comes next, rather than check for userEmail to be null, we just want to check that it's not empty. When you're done, your class should look like this:

public class ShibbolethAutoLogin implements AutoLogin {
private static Log _log = LogFactoryUtil.getLog(ShibbolethAutoLogin.class);
String userEmail = "";
public String[] login(HttpServletRequest req, HttpServletResponse res)
throws AutoLoginException {
String[] credentials = null;
long companyId = PortalUtil.getCompanyId(req);
try {
if (!PrefsPropsUtil.getBoolean(
companyId, PropsKeys.SHIBBOLETH_AUTH_ENABLED,
PropsValues.SHIBBOLETH_AUTH_ENABLED)) {
return credentials;
}
userEmail = (String) req.getAttribute(PrefsPropsUtil.getString(companyId, PropsKeys.SHIBBOLETH_USER_HEADER,PropsValues.SHIBBOLETH_USER_HEADER));
_log.info("User Login received:" + userEmail);
if (userEmail.equals("") || userEmail.length() < 1) {
_log.error("Invalid or missing user login information from Shibboleth");
_log.error("Data returned from attribute:" + userEmail);
return credentials;
}
credentials = new String[3];
User user = UserLocalServiceUtil.getUserByEmailAddress(PortalUtil
.getCompany(req).getCompanyId(), userEmail);
credentials[0] = String.valueOf(user.getUserId());
credentials[1] = user.getPassword();
credentials[2] = Boolean.TRUE.toString();
return credentials;
} catch (NoSuchUserException e) {
_log.error("No user found to match " + userEmail);
} catch (Exception e) {
_log.error(StackTraceUtil.getStackTrace(e));
throw new AutoLoginException(e);
}
return credentials;
}
}

Save the file, and you can now rebuild and re-deploy that plugin. Make sure you completely remove the old Ext plugin per the instructions on the link provided above!

We're not done yet. We need an interface that will let us access these variables. Create a new hook project. Here's a link to how to do it in case you've never created a hook before.
In your new hook project, create this folder structure under WEB-INF/:

jsps/html/portlet/enterprise_admin/settings/

From the corresponding folders in your Liferay source, copy the file authentication.jsp over.
Hate jsps? Yeah, me too. Maybe one day we can go in and convert this stuff into JSF. For now, we play the hand we're dealt.
What you'll see when you open this file is the code that sets up the Authentication settings in Portal Settings. At the top is yet another long series of variable declarations. Add these to the list:

boolean shibbolethAuthEnabled = ParamUtil.getBoolean(request, "settings--" + PropsKeys.SHIBBOLETH_AUTH_ENABLED + "--", PrefsPropsUtil.getBoolean(company.getCompanyId(), PropsKeys.SHIBBOLETH_AUTH_ENABLED, PropsValues.SHIBBOLETH_AUTH_ENABLED));
String shibbolethUserHeader = ParamUtil.getString(request, "settings--" + PropsKeys.SHIBBOLETH_USER_HEADER + "--", PrefsPropsUtil.getString(company.getCompanyId(), PropsKeys.SHIBBOLETH_USER_HEADER, PropsValues.SHIBBOLETH_USER_HEADER));

These declarations are referencing our friends, the value pairs in Liferay. At last we'll be writing code to set them.
Near the top of the HTML you'll see a <liferay-ui> tag with an attribute called "names." That attribute sets up the list of tab links to choose from in the menu. You should see the names of all the existing Web SSO providers. Just add "Shibboleth" to the end of the list.
Next, we see a series of <liferay-ui:section> tags. Each of these sections corresponds to one of the Web SSO providers. Add a new section to the end that looks like this:


<liferay-ui:section>
<aui:fieldset>
<aui:input inlineLabel="left" label="enabled" name='<%= "settings--" + PropsKeys.SHIBBOLETH_AUTH_ENABLED + "--" %>' type="checkbox" value="<%= shibbolethAuthEnabled %>" />

<aui:input cssClass="lfr-input-text-container" label="user-header" name='<%= "settings--" + PropsKeys.SHIBBOLETH_USER_HEADER + "--" %>' type="text" value="<%= shibbolethUserHeader %>" />
</aui:fieldset>
</liferay-ui:section>

And save the file. Now you can deploy your new hook!
When you go to set these values in the Shibboleth configuration in Liferay, they're pretty self explanatory. Just add the name of the Attribute or Header you're being sent from the IdP in the "User Header" box and make sure the "Enabled" box is checked. Save the values.
Now, if the name of the variable ever gets changed, you can just do a quick update right here! (Just make sure you've left yourself a way to bypass Shibboleth and login with Admin privileges without it!)
This has been a pretty complex undertaking and I have no doubt that I've left something out over the course of these 6 posts. Please don't hesitate to leave comments or contact me with questions, and if I've left any glaring holes in these procedures I'll add them in!


Edit:  The complete code for this project can be downloaded as linked in the next post:  Here

---
This project incorporates tools whose development was funded in part by the NIH through the NHLBI grant: The Cardiovascular Research Grid (R24HL085343)

Tuesday, August 23, 2011

Shibboleth and Liferay Part 5: Extending Liferay

This is part 5 of a series of blog posts detailing an approach to using Shibboleth for Web SSO with Liferay.

This is the fun part if you like writing code.

If you've created Ext plugins for Liferay before this will be a piece of cake. If you haven't, check out this post on how to create an Ext plugin project.

So, create your Ext project. I called mine shibauthentication-ext.

Now, within that project, create a folder structure to match Liferay. We're going after the WEB-INF/ext-impl/src/com/liferay/portal/security/auth folder. That'll be in the docroot folder of your project. Now, if you look at the corresponding folder in your Liferay source code you'll notice a series of auto login classes corresponding to the various Web SSO providers Liferay is designed to interact with out of the box. We're going to build one just like them for Shibboleth.

Your new ShibbolethAutoLogin class should be of package com.liferay.portal.security.auth and it should implement AutoLogin.

Here's the code:

public class ShibbolethAutoLogin implements AutoLogin {
private static Log _log = LogFactoryUtil.getLog(ShibbolethAutoLogin.class);
Note the class we're getting the log from. This will be set in the Liferay Admin screen later.
public String[] login(HttpServletRequest req, HttpServletResponse res)
throws AutoLoginException {
String[] credentials = null;
String userEmail = (String) req.getAttribute("[ATTRIBUTE_FROM_IDP]");
_log.info("User Login received:" + userEmail);
The IdP will send the user meta data by a series of header or attribute names. This is the tricky part because depending on how your IdP is configured, it could come in as either Attributes or Headers. Also, this code is assuming you're getting an E-mail address. It could be a username or user ID depending on your IdP. You'll also need to know the name of the attribute itself.

Sometimes people like to iterate through the Enumeration of Attribues or Headers that come in from the HTTP request to see what's coming in. That's fine, but there's a quirk in the servlet running this that will not show the added Attribute from Shibboleth. You need to specify the name in order to access it, which means you have to get your IdP team to tell you what it is or view the Shibboleth Status page to see the list of what's coming in.
if (Validator.isNull(userEmail) || userEmail.length() < 1) {
_log.error("Did not receive user login information from Shibboleth");
_log.error("Data returned from attribute:" + userEmail);
return credentials;
}
try {
credentials = new String[3];
_log.debug("Company:" + PortalUtil.getCompany(req).getCompanyId());
User user = UserLocalServiceUtil.getUserByEmailAddress(PortalUtil
.getCompany(req).getCompanyId(), userEmail);
_log.debug("UserId:" + String.valueOf(user.getUserId()));
credentials[0] = String.valueOf(user.getUserId());
credentials[1] = user.getPassword();
credentials[2] = Boolean.TRUE.toString();
The credentials array is what gets passed to Liferay with the information about the user to be logged in.
_log.info("Logging in user " + userEmail);
return credentials;
} catch (NoSuchUserException e) {
} catch (Exception e) {
_log.error(StackTraceUtil.getStackTrace(e));
throw new AutoLoginException(e);
}
return credentials;
}
}
Again, your situation may be a little different so it's important to understand how this code works so you can adjust it to fit your needs.
Now, there's one more thing that needs to happen before this will work. You have to go into your portal-ext.properties file and tell it to use this module.
#Shibboleth Auto Login Setup
auto.login.hooks=com.liferay.portal.security.auth.ShibbolethAutoLogin, com.liferay.portal.security.auth.RememberMeAutoLogin
auth.pipeline.enable.liferay.check=false
Last, it's nice to get logging from this module so from in Liferay, logged in as an Admin, go to the Control Panel and then go into "Server Administration." Click "Log Levels."

Click "Add Category."

In the box, add com.liferay.portal.security.auth.ShibbolethAutoLogin and click "save."

I'm still working on a hook that would allow the user to select Shibboleth from the Authentication configuration menu just like any other SSO provider. Once it's finished I'll post it here as a final step to make this solution truly integrated.
---
This project incorporates tools whose development was funded in part by the NIH through the NHLBI grant: The Cardiovascular Research Grid (R24HL085343)

Shibboleth and Liferay Part 4: Configuring Tomcat

This is part 4 of a set of blog posts detailing the setup to have Shibboleth provide Web SSO for Liferay.

By this point you've installed Shibboleth, configured Apache and setup your connector between Apache and Tomcat.


Notice, in the last blog post, that we set the port for the AJP connector to port 8009. You're going to need to tell Tomcat to listen on that port. Open up your [Tomcat Home]/conf/server.xml file. About halfway through the file you'll see a few <Connector> tags that define the ports Tomcat is set to listen to. Usually the connector for port 8009 is available by default, which is fine, but notice there's a setting in it: "redirectPort="8443" that redirects any request on port 8009 to 8443... But by default, the Connector for port 8443 is commented out. Go figure.

First, add the following setting to the Connector for port 8009:

tomcatAuthentication="false"

Next, uncomment the Connector tag and settings for port 8443. You'll also need to add the keystoreFile setting to point to the location of your SSL Certificate keystore, as well as the keystorePass. If you created your own self-signed certificate for testing, then you know these values. Otherwise you will need to obtain them from whomever set it up.

Shibboleth and Liferay Part 3: Connecting Apache to Tomcat

This post is the third part in a series describing how to set up Shibboleth as a Web SSO provider to Liferay. By this point you've installed Shibboleth onto your server and have configured Apache to work with it.

Apache is a web server, not a servlet container. Liferay (Or whatever Java based application you're protecting with Shibboleth) must be run in a servlet container. The problem is that Shibboleth only knows how to interact with Apache. Thus, we need to have Apache deal with Shibboleth but still pass requests along to Tomcat.

In order to handle passing requests back and forth between Apache and Tomcat, you'll need to add a module to Apache that will do this for you. If you do a web search on connectors between Apache and Tomcat you'll see a lot of mod_jk and mod_proxy coming up. Most of it seems to revolve around mod_jk.

You do NOT need to use mod_jk with Tomcat 6 and Apache 2.2. You can, but DON'T. It's much more complex to configure, it may not already be installed in your Linux (meaning you get the fun of doing that yourself) and it's not going to be supported much longer (if it even still is.) Just use mod_proxy_ajp.

Seriously.

Proxy Settings

Now, if your httpd.conf contains a separate file for setting up proxies, it's probably called something like proxy_ajp.conf. If not, create it. Open it up. (Make sure your httpd.conf file includes this one, per the previous blog post.)

At or near the top of the file should be the line

LoadModule proxy_ajp_module modules/mod_proxy_ajp.so

This loads the mod_proxy_ajp.so module into Apache on startup.

Make sure the following lines are in the file:

ProxyRequests Off
ProxyPass / ajp://localhost:8009/
ProxyPassReverse / ajp://localhost:8009/
<Proxy *>
Order Deny,Allow
Allow from All
</Proxy>

Now, this will only work if your Liferay is installed as the ROOT application in your Tomcat, as it is in the bundle. If it isn't, you'll need to specify the name of the folder where your Liferay is, for example:

ProxyRequests Off
ProxyPass / ajp://localhost:8009/myliferay/
ProxyPassReverse / ajp://localhost:8009/myliferay/
<Proxy /myliferay/>
Order Deny,Allow
Allow from All
</Proxy>

This also works, of course, for whatever web application you're protecting with Shibboleth.

Now you can save and close that file.

To be continued...

Shibboleth and Liferay Part 2: Configuring Apache

This is part 2 of a set of blog posts detailing the procedure for setting up Shibboleth to provide Web SSO functionality to Liferay.

This is the part that sounds a LOT more complicated than it is.

Apache's configuration is handled in a file called httpd.conf. This file is usually found in the/etc/httpd/conf directory.

There are a few settings in this file we need to pay attention to, but keep in mind that often additional configuration items are kept in separate files and imported into httpd.conf. This allows the user to more easily keep track of related configuration items without having to navigate through one, massive file. if that's the case on your server, then somewhere in your httpd.conf file (usually near the beginning) there should be a statement that looks like this:

Include conf.d/*.conf

That statement is telling Apache to include all the files in the subdirectory conf.d that end in .conf. Yours should be similar. It may also include specific individual files.

General Settings

Open up your httpd.conf file and find your way to the ServerName setting. Set this to the name of the server. That's NAME not IP ADDRESS. The next setting below that should be UseCanonicalName. Set that to "On" in order to get the server to use the ServerName you just set. So if our server is named test.awesome.server.dude then your configuration should look like this:

ServerName test.awesome.server.dude
UseCanonicalName On

And leave the rest alone... Maybe. If your configuration is spread out over multiple separate configuration files as described above, then the rest of this will probably be located in those files. Otherwise stay in httpd.conf to do the rest.

Shibboleth Settings

Next, you should have a file called shib.conf in the directory where all of your other Include files are. It will have been pre-generated for you in some cases by the Shibboleth installation, otherwise these settings should appear in your httpd.conf file. Most of these can be left alone, but the Location tag is the one we're interested in. When Liferay is bundled with Tomcat it is the ROOT application, so for the location in the following setting, we just use / alone.

<Location />
AuthType shibboleth
ShibRequestSetting requireSession 1
require valid-user
</Location>

If your Liferay were installed in Tomcat as some other context, then the name of the folder in [Tomcat Home]/webapps/ would be the correct Location setting.

And that's it for the Shibboleth configurations in Apache.

To be continued...

Tuesday, August 16, 2011

Shibboleth and Liferay Part 1: Installing Shibboleth

So here we go... A topic everybody seems to search on and nobody has a truly complete source of information for. Plenty of guides exist out there for setting up Apache, installing Shibboleth, setting up mod_proxy...

Some of those sites are great, some of them not so much... But the problem is they often assume a LOT about your knowledge of the subject or how your server is configured, and leave out many things important to new people.

That's the sort of problem that led to this blog. So often, blog posts, articles and forum posts are more about showing off than about actually helping people out. Figuring this thing out has been downright PAINFUL, and I want to spare the next guy by sharing lessons learned.

Oh, and many of the links out there referencing the Shibboleth Wiki are broken. They still link to a site that gives you a new URL for the Shibboleth Wiki, but you lose the specific item you were trying to read.

The project we'll be doing here will be an effort to set up Liferay to be protected by Shibboleth as a Web SSO service provider. This will be a series of blog posts detailing each step. Some of these steps aren't unique to Liferay or Tomcat so I'll break them up so if, for example, someone is looking for ways to connect Apache to Tomcat but isn't using Liferay, they can still benefit from this.

If you've been working with Liferay in just Tomcat (Or Oracle or Glassfish or whatever) you may not have had to interact with Apache. Apache is the quiet little web server that comes bundled with Linux and usually stays out of Tomcat's way. Well, now Apache is going to OWN Tomcat. Seriously. When we configure this thing Apache will decide what requests get sent to Tomcat and which ones don't. Tomcat's just going to have to learn to like it.

Here's how it works:

The user makes a request to the server. Shibboleth, having been configured to watch for this request, intercepts it and redirects the user to a separate authentication site. The user logs in using their credentials. Once they're authenticated, the request returns to the original server and Shibboleth then allows the request to proceed. Normally, with a site running under Apache, the request is turned over to Apache and the requested page is transmitted to the client. In the case of a request made to a servlet, more needs to happen. Apache will forward the request along to Tomcat, which will then handle it normally.

Technically, there are two halves of Shibboleth... The Service Provider (SP) and the Identity Provider (IdP). We're only going to worry about the SP here because that's the part that you, the person who's responsible for building this thing, are responsible for. Typically you'll be setting up a site that authenticates through a pre-existing IdP anyway so that part will already be done.

So our software today:
Operating System: (Linux) CentOS 5.6
Web Server: Apache 2.2.3
Web SSO Provider: Shibboleth 2.0
Servlet Container: Tomcat 6.0.29
Portal: Liferay 6.0.6

Step 1: Install Shibboleth

First thing's first... Install Shibboleth. If you're using the same OS I am, you can run this command:

sudo wget http://download.opensuse.org/repositories/security://shibboleth/CentOS_5/security:shibboleth.repo -P /etc/yum.repos.d

then navigate to /etc/yum.repos.d and run this command:

sudo yum install shibboleth.x86_64

If you're not, here's a WORKING link to the Shibboleth Wiki Linux install page.

Now, there are a couple of folders where log files will be written, and you need to make sure that the directory permissions are set such that Shibboleth can use them. These directories are

/var/log/httpd and
/var/log/shibboleth

The files that will be created are /var/log/httpd/native.log and /var/log/shibboleth/shibd.log. Don't create those files... Shibboleth will handle that. This is just so you know.

There is a file, located in /etc/shibboleth called shibboleth2.xml. This file contains the settings to allow Shibboleth to find and use the specific data items that control your authentication. In most cases, if you're working with a pre-existing IdP this file may be provided to you by the team that is responsible for that IdP. If not, a sample file is created for you that you can modify to your needs.

The first important part of that file is the RequestMapper section. It will look like this, assuming Liferay is installed in the ROOT and using the server name we came up with above.

<RequestMapper type="Native">
<RequestMap applicationId="default">
<Host name="test.awesome.server.dude" port="443" scheme="https">
<Path name="/" authType="shibboleth" requireSession="true"/>
</Host>
</RequestMap>
</RequestMapper>

Now, if this file wasn't provided to you by your IdP personnel then you're going to have to configure that part yourself. After RequestMapper is the ApplicationDefaults section. The opening tag for that section should look like this:

<ApplicationDefaults
entityID="https://test.awesome.server.dude/shibboleth"
REMOTE_USER="eppn persistent-id targeted-id"
attributePrefix="AJP_">

Inside this Element is another tag, <Sessions> which has yet another inside that, which we need to configure:

<SSO entityID="https://youramazingidpprovider/idp/shibboleth"
discoveryProtocol="SAMLDS" discoveryURL="https://ds.example.org/DS/WAYF">
SAML2 SAML1
</SSO>

These settings will vary depending on how the IdP is configured, and I'm afraid configuring an IdP is beyond the scope of this blog. There may be additional configuration items as well. If you're stuck having to set that up too, here's a link to the Shibboleth IdP setup page.

Save that file and be sure to start Shibboleth.

sudo /usr/sbin/shibd -fc /etc/shibboleth/shibboleth2.xml

To be continued...




Wednesday, August 10, 2011

Open Source vs. Proprietary Solutions

I haven't posted in a while because we've been working on a new portal that will use Shibboleth as the authentication provider.

Once it's up and running I plan to share the details here in this blog, but for now I can tell you that if ever there was a perfect example of the stark contrast between building websites in the open source world and building them in the proprietary software world, this is it.

I used to be a Microsoft .NET developer. I loved C# and hated having to code in VB.NET or J#. In any case, web development and associated activities in the .NET world are much, much easier than in the Java world. This is both good and bad.

It's good, in that it allows for people of a relatively lower skill level to contribute and fill a niche where you need decent websites built but don't really need for every one of them to be a web guru. It's also bad, in that it really hides a lot of what's going on from the developer, and that can be a real disadvantage if the scope of their responsibilities change to the point where they need to know it.

The Java world is a world of open source, of a thousand solutions to any given problem and a world of completely unshackled creativity. Good stuff, but you'd better know what you're doing or it's amazing how fast you can get in over your head. A thousand solutions to any problem may sound great, except that there's really no way to know which solution is best for you without a thorough understanding of what's going on and what to do with it.

So it has been with this portal project.

My initial plan was to build the portal and have it accessible by Shibboleth using the casshib extension. You see, Liferay doesn't come with out-of-the-box compatibility with Shibboleth (at least, not explicitly) but it does come with explicit support for CAS. Casshib sort of acts as an adapter so you can use Shibboleth to provide the authentication and then pass it to Liferay as if it were coming in the format for CAS.

Making casshib work in a case like this is a configuration nightmare of epic proportions if you've never worked with these things before.

If you're a Liferay developer, and you aren't afraid to open up the Liferay source code and tinker with it a little, there is absolutely no earthly reason to use casshib. No offense to you casshib guys. Your tool would be very useful in cases where an app absolutely had to use CAS but all that's available is Shibboleth. With Liferay however, it does NOT absolutely have to use CAS over Shibboleth.

Converting Liferay to play nice with Shibboleth is surprisingly easy, and once I've had the opportunity to test the code and procedure I'll post the details here. In short, my approach at this point has been to create a Liferay Hook Plugin (to modify the Authentication configuration page) and an Extension Plugin (to add the code to handle Shibboleth) and make the appropriate configuration changes in portal-ext.properties.

The hard part has been getting Shibboleth, Apache and Tomcat to work together with SSL. This too is a problem with a thousand solutions and I expect to have locked ours down in the next couple of days.

If this had been a SiteMinder authentication setup using IIS and a SharePoint portal or something, this all would probably be very easy and quick. The downside is that I'd have learned very little about how these things work, and it would have cost us a whole LOT of money to get there. I don't mean that as a criticism of Microsoft, only that for me personally, I feel like a stronger developer for having had this experience, and I'm glad of it.