 | Level: Introductory Todd Kaplinger (todkap@us.ibm.com), Project Zero Architecture & Development, IBM Gang Chen (gangchen@us.ibm.com), IBM Software Services for WebSphere, IBM
19 Feb 2008 Access control-based security of application resources is one of the core features of Project Zero. OpenID is an open source, emerging security technology that provides decentralized authentication across the Internet. It is increasingly gaining the interest of the Web community. Project Zero adopted this new technology as part of its security offering. In this article, the third and final part of the series, learn about Project Zero Security and how to leverage OpenID authentication, define security rules for the application, and extend a user registry.
Editor's note: IBM® WebSphere® sMash and IBM WebSphere sMash Developer Edition are based on the highly acclaimed Project Zero incubator project. Project Zero is the development community for WebSphere sMash and will continue to offer developers a cost-free platform for developing applications with the latest builds, the latest features, and the support of the community.
Introduction
Before jumping into the introduction of OpenID authentication, we will quickly review what Project Zero is. Below is a quote taken from the Project Zero site:
Project Zero is an incubator project started within IBM that is focused on the agile development of the next generation of dynamic Web applications. Project Zero introduces a simple environment for creating, assembling, and executing applications based on popular Web technologies. The Project Zero environment includes a scripting runtime for Groovy and PHP with application programming interfaces optimized for producing REST-style services, integration mash-ups, and rich Web interfaces.
 |
What's in this article?
This article, the final in the three-part series, delves into Project Zero Security and how to leverage OpenID authentication, define security rules for the application, and extend a user registry. It assumes that you have downloaded Project Zero and either completed the introductory exercise or written a simple application yourself. |
|
Because Project Zero's main target is the next generation of dynamic Web applications
(typically categorized under the Web 2.0 umbrella), it focuses on interactive Web
applications leveraging user-provided content in applications such as mash-ups, wikis,
and blogs. Securing your Web site becomes increasingly critical in the Web 2.0 era,
given the focus on user-generated content. Authenticating your site's users is one such critical security requirement. Traditionally, Web sites have maintained their own authentication systems internally—including providing a user registry to store the end user’s digital identity.
Enter OpenID. OpenID technology provides a decentralized authentication model enabling
Internet single sign-on (SSO). It provides end users with a single digital identity that they can use across the Web. With OpenID, end users can own an identity without externalizing information they would prefer to protect, such as their e-mail address. Figure 1 illustrates key entities in the OpenID authentication architecture:
 |
What is OpenID?
The OpenID Foundation describes OpenID as an open, decentralized, free framework for
user-centric digital identity. OpenID takes advantage of already existing Internet
technology (URI, HTTP, SSL, Diffie-Hellman) and realizes that people are already creating
identities for themselves whether it be at their blog, photostream, profile page, and so
on. With OpenID you can easily transform one of these existing URIs into an account you
can use at sites which support OpenID logins. |
|
Figure 1. OpenID architecture
The OpenID provider (sometimes also referred to as the identity provider) offers the services of registering a user identity and providing OpenID authentication. The replying party is the Web site that needs to authenticate a user. Rather than using the pair of username and password, the user now uses a single OpenID identifier, normally as a URL (Uniform Resource Locator) or XRI (eXtensible Resource Identifier), to access a site.
To support this decentralized authentication model, Project Zero provides an OpenID
consumer library that allows applications to authenticate against a third-party OpenID
identity provider. This lets application developers offload the task of user profile
management to a third-party trusted resource, so they can concentrate on developing the application.
About the examples
To demonstrate OpenID technology with Project Zero and help you gain real hands-on experience, you'll be able to link to examples which you can download and follow through (see Resources). The examples follow a series of use cases with increasing complexity and cover the following common OpenID usage scenarios:
- Example 1 is a basic application that has OpenID configured as the authentication type.
- Example 2 builds upon Example 1 but includes how to provide a custom user registry to deal with the various formats for openid_urls.
- Example 3 builds upon Example 2 but includes support for providing a "white list" of supported OpenID providers that the application will allow.
You'll need an OpenID account
The first step you need to complete is to register for an OpenID account. The Resources section provides a link to OpenID.net, which lists
various commonly used OpenID providers. For this article, we will use one of the most common OpenID providers, myopenid.com, and a test OpenID provider that is being used as a proof-of-concept for OpenID at IBM. (Note that the application demonstrated in this article should work with any OpenID provider that supports the OpenID specification.)
Example application #1: Enabling OpenID authentication
To better understand the Project Zero OpenID technology, you can download the sample application named openid.demo used in this article from the Project Zero Catalog (see Resources) and review the application while following the discussion. You need to have the Eclipse development IDE and Project Zero plug-in properly configured. (A link to the plug-in is listed in the Resources section. You can reference this article for the setup.) When ready, import the sample application (named openid.demo-1.0.0.zip) as the Existing Project into Workspace. Select archive file as source (see Figure 2). Project Zero provides OpenID support through the zero.security.openid library, which has been configured as one of the application dependencies in the ivy.xml file. If this is your first time using OpenID, you may be asked to download the zero.security.openid library into your repository.
Figure 2. Import the example application
Click OK to resolve the dependencies.
The example application has just two Web pages—an example of the radical simplicity of Project Zero. The first is an index page (see Figure 3) that contains a text area where users can post comments. When the comments are posted, the application uses Ajax technology to send a RESTful request to the server to submit the message. Then, the application makes another Ajax call to obtain the message from the server back to the browser. While this is not a particularly useful application, it will provide enough functionality to demonstrate how OpenID works in Project Zero. To run the sample application, right click the OpenIDExampleApplication and select Run as – Project Zero Application. Your server component is up and running. Now, direct your browser to the http://localhost:8080 to test the sample application (see Figure 3).
Figure 3. Index page for the OpenID example application (index.gt)
The sample application uses a groovy component (comment.groovy; see Listing 1) to handle posting and getting comments.
Listing 1. comment.groovy RESTful service used for posting and getting comments
def onCreate(){
def commentJSON = zero.json.Json.decode(request.input[])
def comment = commentJSON["comment"]
if(comment != null || comment == ""){ // user submitted a comment with content
def commentId = "Comment_" + System.currentTimeMillis()
request.headers.out.Location =
zero.core.utils.URIUtils.getRequestedUri(false) + "/" + commentId
user.commentId = comment;
request.status = java.net.HttpURLConnection.HTTP_NO_CONTENT
}
}
def onRetrieve(){
def commentId = request.params.commentId.get()
def comment = user.commentId.toString();
def result = [commentId : comment]
request.view='JSON'
request.json.output = result
zero.core.views.ViewEngine.render()
}
|
Configuring security for the example application
Now with the sample application ready, we need to secure these resources to prevent
non-authenticated users from accessing this site. Because we want to avoid having to
create and maintain another Web page and a user registry to allow users to create and
store accounts (userid and password), we decided to defer authentication to a third
party while allowing our site to remain secure. We'll leverage the OpenID support
provided by Project Zero to achieve this and to worry about configuring the proper security rules.
To enable OpenID authentication, you need to specify two configuration stanzas in the application zero.config file as summarized in Table 1.
The first configuration stanza is global to the application. Table 1 describes two configuration keys (openidLoginPage and allowedOpenidDomains) which are both optional.
Table 1. OpenID application configuration
| Key | Description | Default Value | Mandatory? |
|---|
| openidLoginPage | URI for OpenID login form | openidLogin.html | Optional | | allowedOpenidDomains | List of trusted OpenID provider domain names | Empty | Optional |
To enable the OpenID authentication for our example application, the first step is to configure the zero.config global configuration for the application. In this stanza, we will define just the OpenID login page that lets the user enter their openid_url (identifier) for authentication.
Listing 2.
Configure OpenID example—app configuration
# specify the OpenID loginPage
@include "openid/rule.config"{
"openidLoginPage": "/openidlogin.gt"
}
|
The second step is to configure the resources to apply security constraints. Three separate configuration settings are defined in these stanzas, as follows:
-
Stanza 1: Defining a role
In Stanza 1, we define a role, which is being seen for the first time in the article and
is considered to be an advanced topic for Project Zero Security. The role being defined is called OPENID_ROLE, and all users that are members of the group are called VALID_OPENID_USER.
-
Stanza 2: Defining a security constraint for OpenID
In Stanza 2, we define a security constraint for index.gt, which is the entry point of the application. For this constraint, the role defined in the first stanza is listed as a required role for this resource. The authType for this resource is defined as RP. (RP standards for Relying Party with the only currently supported RP type being OpenID.) If a resource is protected with an authType of RP and a user is not considered logged in, the user will be redirected to the appropriate login page to authenticate.
-
Stanza 3: Defining a security constraint for a RESTful service
In Stanza 3, we define a security constraint for comment.groovy which is the RESTful
resource handling our AJAX services. For this constraint, the ROLE defined in the first
stanza is listed as a required ROLE for this resource. The authType for this resource is
SSO (single sign-on). The reason why this resource is protected using SSO is for convenience and style. If this resource was protected using an authType of RP and the security token is expired, the AJAX request would be redirect to a login page. While this is acceptable for non-AJAX requests, it really does not provide a good user experience for AJAX style requests. If a user is not authenticated when trying to access this resource, the user will receive a 401 status code and the application can provide a special error handler to deal with that condition.
Listing 3.
Configure OpenID example—resource security
## define a role named OPENID_ROLE that only the group VALID_OPENID_USER is a member
/config/security/roles/OPENID_ROLE/groups=["VALID_OPENID_USER"]
#specify the security constraints
#protect index page
@include "security/rule.config"{
"conditions" : "/request/path =~ (/|/index.gt(/.*)?)",
"authType" : "RP",
"csrfProtect" : false,
"roles" : ["OPENID_ROLE"]
}
#protect RESTful resource with SSO so no redirects
#to login page for the case of expired tokens.
@include "security/rule.config"{
"conditions" : "/request/path =~ /resources/comment(/.*)?",
"authType" : "SSO",
"csrfProtect" : true,
"roles" : ["OPENID_ROLE"]
}
|
Accessing the secured resource
After creating a user ID (see the section, "You'll need an OpenID
account"), you are now ready to access the application. The first step is to open a browser and attempt to access http://localhost:8080/index.gt, which is the main entry point in the application. Because that resource is secured with the authType of RP, the Zero Security runtime will notice that the resource is protected and redirect the user to the openidLoginPage that was defined above. You should now see the following in your browser (see Figure 4).
Figure 4. Login form for OpenID example application (openidlogin.gt)
The login form will contain the following code format shown in Listing 4 and will be named openidlogin.gt.
Listing 4. openidlogin.gt login form html
<form name="input" action="" method="POST">
<table>
<tr>
<td class="header">OpenID URL: </td>
<td><input type="text" name="openid_url" value=""></td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" name="submit" value="Login"></td>
|-------10--------20--------30--------40--------50--------60--------70--------80--------9|
|-------- XML error: The previous line is longer than the max of 90 characters ---------|
</tr>
</table>
</form>
|
At this point, we will use the openid_url (todkap.myopenid.com) that was provided by myopenid.com to log in. With OpenID, the login request will be redirected over to the myopenid.com site and start the authentication process on that site with the appropriate opened_url and password (see Figure 5).
Figure 5. Login form for myopenid.com
After successfully authenticating with the OpenID provider (myopenid.com), the OpenID provider will redirect the client back to the originally requested page (http://localhost:8080/index.gt), which we have now enhanced to show the RemoteUser, groups, and roles the user is a member of. The RemoteUser will be the openid_url that was used to log in. The groups will contain a single group called VALID_OPENID_USER, and the role will be populated with OPENID_ROLE. If this is not the case, the user would not be authenticated because only users in the role OPENID_ROLE are permitted to access this resource. Figure 6 shows what the browser should display after successful authentication.
Figure 6. Index page after user is logged in
Now, you can safely post a comment about what a good day today is.
Example application #2: Extending OpenID support with Project Zero
Now that the basic OpenID support is working, we want to extend the default event handler and the default user registry implementations so that the OpenID account can be converted to a supported Project Zero local account. This is extremely useful when bridging the Internet SSO with a corporate intranet security system.
Defining a custom resolveFederatedId event handler
The resolveFederatedId is an event handler that is fired
between the secure and authorization events in request processing. This event is added
specifically in a case where a user logged in using a federated ID (for instance,
openID). Sometimes, the user ID may need some modification (or transformation) in order
to be used by both the third-party authenticator and Project Zero's user registry. In a
case where the openid_url is owned by the internal OpenID provider (for example,
'blueid.bluehost.ibm.com' for IBM internal OpenID authentication), you can refer to just the e-mail address. IBM uses the e-mail address for various other SSO solutions in addition to dealing with the IBM directory. Listing 5 shows a handler that extends the default implementation of OpenIDResolver. It overrides the attachUserToken method call that is invoked when the default implementation is called to create a token used to identify the client for secured requests after the initial login. The overridden attachUserToken takes the authenticated username as an argument and checks to see if it starts with the variable TRUSTED_OPENID_SERVER. If there is a match, it removes that from the beginning of the user name.
Listing 5. Custom resolveFederatedId event handler code
package zero.security.example.openid;
import zero.core.security.relying.party.openid.OpenidResolver;
public class ExampleOpenidResolver extends OpenidResolver{
private static final String TRUSTED_OPENID_SERVER =
"http://blueid.bluehost.ibm.com/?user=";
@Override
public void onResolveFederatedId() {
super.onResolveFederatedId();
}
@Override
protected void attachUserToken(String username) {
if (username.startsWith(TRUSTED_OPENID_SERVER)){
// consider this user trusted for this app and
//just use the userid in token and remoteUser
username = username.substring(TRUSTED_OPENID_SERVER.length());
}
super.attachUserToken(username);
}
}
|
The following configuration stanza shown in Listing 6 defines how to configure the custom resolveFederatedId handler. The download example has these lines commented out. To test in your environment, be sure to uncomment these configuration items.
Listing 6. Custom resolveFederatedId configuration
/config/handlers += [{
"events" : "resolveFederatedId",
"handler" : "zero.security.example.openid.ExampleOpenidResolver.class"
}]
|
Defining a custom UserService implementation
In addition to adding a custom resolveFederatedId, we decided to also demonstrate how to create a custom UserService. In the example shown in Listing 7, we extend the default UserService implementation that is used for OpenID authentication. In the custom implementation class, we call the default implementation getUser and login to get the appropriate set of user principals. Then we add a custom group called DWExampleGroup to demonstrate how to add additional groups for a particular user. While the custom resolveFederatedId is only checking for the internal IBM OpenID provider, the custom UserService will add this custom group regardless of the OpenID provider.
Listing 7. Custom UserRegistry implementation code
package zero.security.example.openid;
import java.security.Principal;
import java.security.acl.Group;
import java.util.Set;
import zero.core.security.GroupImpl;
import zero.core.security.relying.party.openid.OpenIDUserService;
import zero.core.security.userservice.UserServiceException;
public class ExampleUserService extends OpenIDUserService{
private static final Group DW_GROUP = new GroupImpl("DWExampleGroup");
@Override
public Set<Principal> getUser(String username)
throws UserServiceException {
Set<Principal> principals = super.getUser(username);
if(principals.isEmpty() == false) { // user was logged in via openID
principals.add(DW_GROUP); // add developer work group
}
return principals;
}
@Override
public Set<Principal> login(String username, String passwd)
throws UserServiceException {
Set>Principal< principals = super.login(username, passwd);
if(principals.isEmpty() == false) { // user was logged in via openID
principals.add(DW_GROUP); // add developer work group
}
return principals;
}
}
|
The following configuration stanza in Listing 8 defines how to configure the custom UserService.
Listing 8. Custom UserService configuration
registryImplStr="zero.security.example.openid.ExampleUserService"
/config/security/userservice/registryType="exampleUserService"
# must implement zero.core.security.userservice.UserService
/config/security/userservice/registryImpl/exampleUserService=${registryImplStr}
|
Demonstrating example #2
Now that we have the application configured with the custom resolveFederatedId and UserService implementations, the application needs to be restarted for configuration to take effect. We will now access the secured application again. In the prior example, we used the openid_url of todkap.myopenid.com. Now, we are going to use the openid_url of http://blueid.bluehost.ibm.com/?user=todkap@us.ibm.com, which will demonstrate the features of the new configuration.
We start off on the same login form as before. However, this time we log in with the openid_url of http://blueid.bluehost.ibm.com/?user=todkap@us.ibm.com from the IBM OpenID service. This will redirect the user to the OpenID Provider login page (see Figure 7):
Figure 7. Login form for IBM OpenID Provider
Instead of the myopenid.com, the authentication request is now routed to the IBM intranet
OpenID site, blueid.bluehost.ibm.com. After successfully authenticating with the OpenID
provider, the OpenID provider will redirect the client back to the originally requested
page (http://localhost:8080/index.gt), which we have now enhanced to show the RemoteUser,
groups, and roles the user is a member of. What is different now is that the remote user
will be the modified version of the openid_url that was used during login. (Note: This
userid is modified by the resolveFederatedId to be just the e-mail address of the user.)
The groups will contain two groups: the original 'VALID_OPENID_USER' and newly added
'DWExampleGroup' through the UserService. In the meantime, the role will be populated with OPENID_ROLE. If this is not the case, the user would not be authenticated because only users in the ROLE 'OPENID_ROLE' are permitted to access this resource. Figure 8 shows what the browser should display after successful authentication.
Figure 8. Index page after user is logged in
Now, you can comment on what an even better day today is.
Example application #3: Using only trusted OpenID providers
We have now shown how to leverage OpenID in two common scenarios. One of the downsides
of OpenID is that any site exposing an OpenID provider service can claim a user's
identity is valid. This poses a challenge for the replying party (your Web site) to
trust all those claims. To assist in limiting this exposure, Zero provides a
configuration option to limit which sites the application will trust as OpenID
providers. The following example in Listing 11 demonstrates how to enable this
configuration, and what happens if the openid_url specified is from an untrusted domain.
Note that while this could be done on the client side through JavaScript code, there should always be validation on the server to prevent possible circumventions on the client.
Listing 9. Configuring a white list of trusted OpenID providers
@include "openid/rule.config"{
"openidLoginPage" : "/openidlogin.gt",
"allowedOpenidDomains" = ["myopenid.com", "verisignlabs.com", "blueid.bluehost.ibm.com"]
|-------10--------20--------30--------40--------50--------60--------70--------80--------9|
|-------- XML error: The previous line is longer than the max of 90 characters ---------|
}
|
Now that we have configured this option and restarted the application, we will try an
untrusted OpenIDProvider. In this example, we will use a fictitious openid_url called 'http://myuntrusteduser.someunknownsite.com'. This results in the following exception being logged to the client for instances where the openid_url provider is not listed in the list of allowedOpenidDomains (see Figure 9).
Figure 9. Untrusted OpenId provider error page
Conclusion
OpenID provides increased flexibility for application deployment by enabling
applications to leverage third-party authentication providers for handling
authentication. Providers such as OpenID have become very common as more users want a
single user profile across multiple sites for blogs, wikis, and other social networking
activities. Additionally, many Web sites do not want to maintain, or require users to
continually provide, the same profile-related information just to ensure that the user
credentials are valid. We hope this final article in the series has helped you learn how to use the OpenID technology in the Project Zero platform to achieve this decentralized authentication, and that the entire series has helped you understand best practices for building the all-important security features into your Zero applications. As a developer of fast-paced, user-driven Web 2.0 applications, you know how vital security is to both your customers and your business.
Resources Learn
- Visit the OpenID Foundation for information on authentication as well as the goals of the Foundation within the open source community.
- For this article, we used one of the most common
OpenID providers, http://www.myopenid.com, and a test OpenID provider that is being used as a proof of concept for OpenID at IBM.
-
OpenID.net lists various commonly used OpenID providers.
-
"Enable C++ applications for Web services using XML-RPC"
(developerWorks, Jun 2006) is a step-by-step guide to exposing C++ methods as
services.
- In the
Architecture area on developerWorks,
get the resources you need to advance your skills in the architecture arena.
- Browse the
technology bookstore
for books on these and other technical topics.
- Refer to the Project Zero Developer's Guide for a complete overview of Project Zero security configuration.
- Because this article assumed that you have already
installed the appropriate Project Zero plug-ins from the Eclipse update site and that
you know how to create a Project Zero application within Eclipse, if you haven't already done so and need to do so, refer to the Core Getting Started page of the Developer's Guide.
- Join the
Project Zero community and see what all the buzz is about!
-
Browse the developerWorks Web development zone to find tools, code, and resources to get you started developing Web 2.0 applications today.
-
The developerWorks Ajax resource
center is packed with information for all skill levels to help you build Ajax into
your applications and dramatically improve your users' Web experience.
Get products and technologies
Discuss
About the authors  | 
|  | Todd Kaplinger is a Senior Software Engineer in IBM's Software Group currently working as Architect and Team Lead of the Security Team for Project Zero. Todd is an expert in Web-based technologies such as JSP, Servlet, and PHP with a recent focus on emerging Web 2.0 technology and its impact on the enterprise. Todd is currently a member of the expert group responsible for JSR 223: Scripting for the Java™ Platform and is also a member of the Open Ajax Alliance with an interest in interoperability between various Ajax framework implementations regarding security. Todd's previous background was as Team Lead and Architect of WebSphere's Webcontainer and Remote Request Dispatcher (RRD) and participated in the JSR 154 Servlet 2.5 Specification as IBM's representative in the Servlet Expert Group. You can reach Todd at todkap@us.ibm.com. |
 | 
|  | Gang Chen is a certified consulting I/T specialist in IBM Software Services for
WebSphere (ISSW). Gang is an expert in helping enterprise customers with their e-business application design and implementation. Recently, he's focused on the emerging Web 2.0 technology to bring value to enterprise customers. He is also one of the authors of the IBM Redbook "IBM WebSphere Application Server V6 Scalability and Performance Handbook." You can reach Gang at gangchen@us.ibm.com. |
Rate this page
|  |