OpenID authentication
OpenID Description
OpenID is completely decentralized, meaning that anyone can choose to be a consumer or identity provider without registering or being approved by any central authority. End users can pick which identity provider they want to use and preserve their identity as they move between providers.
The zero.security.openid package provides an OpenID consumer library that allows applications to use OpenID Identity Providers for third party authentication using the IBM® WebSphere® sMash Security Relying Party interface.
The following sections of this article provide information about OpenID:
Adding zero.security.openid to your application
If you are using OpenID within a WebSphere sMash application, you need to resolve a dependency to install the required jar files. After creating your application, add the following line in the dependencies section of your config/ivy.xml file:
<dependency name="zero.security.openid" org="zero" rev="[1.0.0.0, 2.0.0.0["/>
After adding the dependency, run the zero resolve task from the WebSphere sMash CLI from Eclipse.
Configuring OpenID
To enable OpenID authentication, you need to specify two configuration stanzas as summarized in the following table.
| Key | Description | Default Value | Mandatory ? |
|---|---|---|---|
| openidLoginPage | URI for OpenID login form | Empty | Required |
| allowedOpenidDomains | List of trusted OpenID provider domain names | Empty | Optional (see note below) |
Please be advised that default OpenID configuration is to allow any OpenID Provider for validating whether a user should be trusted. 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 relying party (your Web site) to trust all those claims. To assist in limiting this exposure, WebSphere sMash provides the option (allowedOpenidDomains) to limit which sites the application will trust as OpenID providers. 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.
The following example shows the OpenID application configuration:
# specify the OpenID loginPage
@include "security/openid.config"{
"openidLoginPage": "/openidlogin.gt",
"allowedOpenidDomains" : ["myopenid.com", "verisignlabs.com"]
}
For securing resources, OpenID uses the same configuration as for other authentication types with the authType being RP for relying party authentication. See the Security rules section for more information.
The following example shows an OpenID security constraint configuration:
#specify the security constraints
@include "security/rule.config"{
"conditions": "/request/path =~/protectedResource.groovy(/.*)?",
"authType" : "RP",
"groups" : ["ALL_AUTHENTICATED_USERS"]
}
Creating a login form
OpenID login requires the creation of a login form at the location specified by openidLoginPage. There are several requirements for this form:
- The method must be
POST. - The action must result in the request going to the login page,
openidLoginPage, upon submit. If a user navigates to the login page as a result of directory indexing (for example, requests to the root of the application without a resource explicitly listed), the action needs to beopenidLoginPage. For all other types of requests, the action can be left blank. - The
OpenID Identityfield must be named openid_url (as recommended by the OpenID 2.0 specification).
The following example is a sample form:
<html>
<form method="POST" action="">
<input type="text" name="openid_url" >
<!-- optional hidden value used in requesting unprotected OpenID login page scenario -->
<input type="hidden" name="postLoginTargetURI" value="secure/index.gt">
<input type="submit" value="Submit"/>
</form>
</html>
Form-based security flow
You can request a protected resource or an unprotected form login page, as described in the following sections.
Requesting a protected resource
When a request comes in for a protected resource, the following events take place:- The incoming request is checked for a valid token.
- If a token is:
- Not found or expired:
- A 302 status code is sent to the client to redirect it to the login page (as defined in the configuration file under the
openidLoginPageentry). - A login is attempted with the incoming credentials.
- The server internally connects to a URL specified in
openid_urlto determine the OpenId provider. - The client is redirected to the OpenID provider for authentication.
- If the login is:
- Unsuccessful, the OpenID Provider's login page is returned again.
- Successful, a token is generated for subsequent requests and a 302 status code is sent to the client to redirect it to the original protected resource (or was overriden by the
postLoginTargetURIquery parameter for the OpenID Login Form).
- A 302 status code is sent to the client to redirect it to the login page (as defined in the configuration file under the
- Found, then an authorization check is performed.
- If authorization is:
- Unsuccessful, a 403 unauthorized status header is returned to the client.
- Successful, the protected resource is served.
- If authorization is:
- Not found or expired:
Requesting an unprotected form login page
When a request comes in for the OpenID login page, the following events take place:
- A login is attempted with the incoming credentials.
- If the incoming request for the protected resource contains an invalid or missing token:
- A login is attempted with the incoming credentials.
- The server internally connects to URL specified in
openid_urlto determine the OpenId provider. - The client is redirected to the OpenID provider for authentication.
- If the login is:
- Unsuccessful, the login page is returned again with a 200 status code.
- Successful, a token is generated for subsequent requests and a 302 status code is sent to the client to redirect it to the protected resource (that was stored in the hidden
postLoginTargetURIform field parameter).
- If the incoming request for the protected resource contains a valid token:
- An authorization check is performed.
- If authorization is:
- Unsuccessful, a 403 unauthorized status header is returned to the client.
- Successful, the protected resource is served.
- If the incoming request for the protected resource contains an invalid or missing token:
OpenIDBasedLoginHandler does not receive the parameter postLoginTargetURI, the user is redirected to the context root of the application where the application developer can define a default file resource to handle the request.
Converting an OpenID to a local ID
While the common usage pattern specifies ALL_AUTHENTICATED_USERS as the GROUP associated with the protected resource for OpenID protected resources, you can also convert an OpenID account to a local account using the resolveFederatedId handler and a custom User Registry named zero.core.security.relying.party.userservice.RPUserService. This handler is fired between the secure and authorization events and can be used to do perform a range of functions from converting the userID to an internal alias to adding special GROUPS or ROLES for the authenticated user. By default, a simple resolver populates the /request/subject in the global context with the remoteUser equal to the OpenID and a group called VALID_OPENID_USER.
The following example shows configuration for a resolveFederatedId:
/config/handlers += [{
"events" : "resolveFederatedId",
"handler" : "zero.core.security.relying.party.openid.OpenidResolver.class"
}]
For additional information on how to create a custom user service registry, see the
User Service section.Obtaining an OpenID
There are many ways to obtain a OpenID. See the page on the OpenID.net site that lists the various OpenID providers which are commonly used.