Product SiteDocumentation Site

Belay 1.0

PressGang Belay Developer Guide

Developers' Guide for using PressGang Belay

Edition 1

SkyNet Alpha Build System

Engineering Content Services Red Hat

Legal Notice

Copyright © 2012 Red Hat, Inc.

The text of and illustrations in this document are licensed by Red Hat under a Creative Commons Attribution–Share Alike 3.0 Unported license ("CC-BY-SA"). An explanation of CC-BY-SA is available at http://creativecommons.org/licenses/by-sa/3.0/. In accordance with CC-BY-SA, if you distribute this document or an adaptation of it, you must provide the URL for the original version.

Red Hat, as the licensor of this document, waives the right to enforce, and agrees not to assert, Section 4d of CC-BY-SA to the fullest extent permitted by applicable law.

Red Hat, Red Hat Enterprise Linux, the Shadowman logo, JBoss, MetaMatrix, Fedora, the Infinity Logo, and RHCE are trademarks of Red Hat, Inc., registered in the United States and other countries.

Linux® is the registered trademark of Linus Torvalds in the United States and other countries.

Java® is a registered trademark of Oracle and/or its affiliates.

XFS® is a trademark of Silicon Graphics International Corp. or its subsidiaries in the United States and/or other countries.

MySQL® is a registered trademark of MySQL AB in the United States, the European Union and other countries.

All other trademarks are the property of their respective owners.
Abstract

Belay Reference for Developers
Preface
1. Document Conventions
1.1. Typographic Conventions
1.2. Pull-quote Conventions
1.3. Notes and Warnings
2. Getting Help and Giving Feedback
2.1. Do You Need Help?
2.2. Give us Feedback
1. Introduction to PressGang Belay
1.1. About PressGang Belay
1.2. About PressGang Belay's Documentation
1.3. About This Document's Audience
1.4. About PressGang Belay's Technologies
1.5. PressGang Belay Components
1.6. About GWT
1.7. About the GWT Client Application
1.8. About the GWT Client Provider
1.9. About the Authorization Server
1.10. About the Authorization Server Provider
1.11. PressGang Belay OAuth2 Auth Server Provider Entity Relationship Diagram
1.12. About the OpenID Provider
1.13. About the OAuth2-secured REST App
1.14. About Supported OAuth2 Authorization Flows
1.15. PressGang Belay Public Client Flow
1.16. PressGang Belay Confidential Client Flow
1.17. PressGang Belay Authenticate End-User - All Clients
1.18. PressGang Belay Obtain End-User Authorization - Public Client
1.19. PressGang Belay Obtain End-User Authorization - Confidential Client
1.20. PressGang Belay Request Protected Resource - Public Client
1.21. PressGang Belay Request Protected Resource - Confidential Client
1.22. About the Resource Server Provider Library
1.23. PressGang Belay OAuth2 Resource Server Provider Entity Relationship Diagram
1.24. About PressGang Belay OAuth Tokens
2. GWT Client Provider Library and Sample Application
2.1. Set up the GWT Client Provider Library
2.2. Authorize an End-user with the GWT Client Provider Library
2.3. Make a Request to a Resource Server
2.4. Retrieve End-user Data
2.5. Associate End-user Identities
2.6. Change End-user's Primary Identity
2.7. Clear Stored Tokens
2.8. Invalidate Token Grant
2.9. Retrieve Access Tokens
2.10. Encode a URL
2.11. Prepare the GWT Client Application for Use
3. Resource Server Provider and Sample Application
3.1. Secure RESTful Web Services with the Resource Server Provider Library
4. Authorization Server and Associated Processes
4.1. Set Up an OAuth2 Authorization Server Using the Auth Server Provider Library
4.2. Define Paths For Provided Endpoint Implementations
4.3. Customize Paths For Provided Endpoint Implementations
4.4. Override Auth Server Provider Configuration Options
4.5. Override Default OAuth2 Token Generation Service
4.6. Override Default Auth Service
A. Revision History

Preface

1. Document Conventions

This manual uses several conventions to highlight certain words and phrases and draw attention to specific pieces of information.

In PDF and paper editions, this manual uses typefaces drawn from the Liberation Fonts set. The Liberation Fonts set is also used in HTML editions if the set is installed on your system. If not, alternative but equivalent typefaces are displayed. Note: Red Hat Enterprise Linux 5 and later includes the Liberation Fonts set by default.

1.1. Typographic Conventions

Four typographic conventions are used to call attention to specific words and phrases. These conventions, and the circumstances they apply to, are as follows.

Mono-spaced Bold

Used to highlight system input, including shell commands, file names and paths. Also used to highlight keycaps and key combinations. For example:

To see the contents of the file my_next_bestselling_novel in your current working directory, enter the cat my_next_bestselling_novel command at the shell prompt and press Enter to execute the command.

The above includes a file name, a shell command and a keycap, all presented in mono-spaced bold and all distinguishable thanks to context.

Key combinations can be distinguished from keycaps by the plus sign that connects each part of a key combination. For example:

Press Enter to execute the command.

Press Ctrl+Alt+F2 to switch to a virtual terminal.

The first paragraph highlights the particular keycap to press. The second highlights two key combinations (each a set of three keycaps with each set pressed simultaneously).

If source code is discussed, class names, methods, functions, variable names and returned values mentioned within a paragraph will be presented as above, in mono-spaced bold. For example:

File-related classes include filesystem for file systems, file for files, and dir for directories. Each class has its own associated set of permissions.

Proportional Bold

This denotes words or phrases encountered on a system, including application names; dialog box text; labeled buttons; check-box and radio button labels; menu titles and sub-menu titles. For example:

Choose SystemPreferencesMouse from the main menu bar to launch Mouse Preferences. In the Buttons tab, click the Left-handed mouse check box and click Close to switch the primary mouse button from the left to the right (making the mouse suitable for use in the left hand).

To insert a special character into a gedit file, choose ApplicationsAccessoriesCharacter Map from the main menu bar. Next, choose SearchFind… from the Character Map menu bar, type the name of the character in the Search field and click Next. The character you sought will be highlighted in the Character Table. Double-click this highlighted character to place it in the Text to copy field and then click the Copy button. Now switch back to your document and choose EditPaste from the gedit menu bar.

The above text includes application names; system-wide menu names and items; application-specific menu names; and buttons and text found within a GUI interface, all presented in proportional bold and all distinguishable by context.

Mono-spaced Bold Italic or Proportional Bold Italic

Whether mono-spaced bold or proportional bold, the addition of italics indicates replaceable or variable text. Italics denotes text you do not input literally or displayed text that changes depending on circumstance. For example:

To connect to a remote machine using ssh, type ssh username@domain.name at a shell prompt. If the remote machine is example.com and your username on that machine is john, type ssh john@example.com.

The mount -o remount file-system command remounts the named file system. For example, to remount the /home file system, the command is mount -o remount /home.

To see the version of a currently installed package, use the rpm -q package command. It will return a result as follows: package-version-release.

Note the words in bold italics above — username, domain.name, file-system, package, version and release. Each word is a placeholder, either for text you enter when issuing a command or for text displayed by the system.

Aside from standard usage for presenting the title of a work, italics denotes the first use of a new and important term. For example:

Publican is a DocBook publishing system.

1.2. Pull-quote Conventions

Terminal output and source code listings are set off visually from the surrounding text.

Output sent to a terminal is set in mono-spaced roman and presented thus:
books        Desktop   documentation  drafts  mss    photos   stuff  svn
books_tests  Desktop1  downloads      images  notes  scripts  svgs

Source-code listings are also set in mono-spaced roman but add syntax highlighting as follows:
package org.jboss.book.jca.ex1;

import javax.naming.InitialContext;

public class ExClient
{
   public static void main(String args[]) 
       throws Exception
   {
      InitialContext iniCtx = new InitialContext();
      Object         ref    = iniCtx.lookup("EchoBean");
      EchoHome       home   = (EchoHome) ref;
      Echo           echo   = home.create();

      System.out.println("Created Echo");

      System.out.println("Echo.echo('Hello') = " + echo.echo("Hello"));
   }
}

1.3. Notes and Warnings

Finally, we use three visual styles to draw attention to information that might otherwise be overlooked.

Note

Notes are tips, shortcuts or alternative approaches to the task at hand. Ignoring a note should have no negative consequences, but you might miss out on a trick that makes your life easier.

Important

Important boxes detail things that are easily missed: configuration changes that only apply to the current session, or services that need restarting before an update will apply. Ignoring a box labeled 'Important' will not cause data loss but may cause irritation and frustration.

Warning

Warnings should not be ignored. Ignoring warnings will most likely cause data loss.

2. Getting Help and Giving Feedback

2.1. Do You Need Help?

If you experience difficulty with a procedure described in this documentation, visit the Red Hat Customer Portal at http://access.redhat.com. Through the customer portal, you can:
  • search or browse through a knowledgebase of technical support articles about Red Hat products.
  • submit a support case to Red Hat Global Support Services (GSS).
  • access other product documentation.

Red Hat also hosts a large number of electronic mailing lists for discussion of Red Hat software and technology. You can find a list of publicly available mailing lists at https://www.redhat.com/mailman/listinfo. Click on the name of any mailing list to subscribe to that list or to access the list archives.

2.2. Give us Feedback

If you find a typographical error, or know how this guide can be improved, we would love to hear from you. Submit a report in Bugzilla against the product Belay and the component documentation. The following link will take you to a pre-filled bug report for this product: https://bugzilla.redhat.com/.

Fill out the following template in Bugzilla's Description field. Be as specific as possible when describing the issue; this will help ensure that we can fix it quickly.
Document URL:


Section Number and Name:


Describe the issue:


Suggestions for improvement:


Additional information:


Be sure to give us your name so that you can receive full credit for reporting the issue.

Chapter 1. Introduction to PressGang Belay

1.1. About PressGang Belay

PressGang Belay was created to provide RESTful web service security, with a few particular restrictions in mind. The first was that to avoid handling or storing end-user passwords, the system had to outsource authentication; for this the developers chose to use OpenID. The second design restriction was that the system had to be appropriate for a shared REST interface that also served as the server side of a Google Web Toolkit (GWT) application. It had to be possible to handle authentication/authorization in the browser with the GWT client-side, without relying on any dedicated, GWT-specific server-side. To facilitate this the developers chose to use OAuth2 with its authorization server and resource server model. From the various OAuth2 protocol flows, the developers chose to support the Implicit Flow for public clients and the Authorization Code flow for confidential clients (those capable of securing a client secret). A further design restriction was to be able to use the system both internally and externally. This is another reason the developers chose OpenID; it provides external authentication, and they could standardize on it by creating an internal OpenID provider wrapping internal authentication mechanisms (this is the idea behind the OpenID Provider project). Given these restrictions, creating a suite of components that utilized OpenID and OAuth2 seemed like the appropriate solution. Note that while there is a draft OpenID Connect standard that attempts to combine OpenID and OAuth2, implementing this would not have met the goals of this project because of its architecture. One final restriction on the project was that it had to be possible to select the OpenID providers used, to allow the flexibility to use lesser known providers such as the Fedora Account System and/or a custom provider.

PressGang Belay uses OAuth2 and OpenID to provide filter-based security for RESTful web services, primarily for browser-based applications. Confidential clients without browser access, such as internal terminal applications, can still use the system if issued non-expiring OAuth2 access tokens so no browser-based login process is necessary. Confidential clients with browser access, such as traditional client-server applications, are catered for by endpoints implementing OAuth2's Authorization Code flow. PressGang Belay provides libraries that allow RESTful resource servers and GWT client apps utilizing those web services to be implemented easily. It also provides an authorization server library and sample implementation and an example OpenID provider implementation, which could be used to wrap alternative authentication mechanisms. It is designed to secure RESTful web services, but could potentially be used by any service that can be protected by a filter.

1.2. About PressGang Belay's Documentation

This documentation details PressGang Belay's OAuth2 support and the various components that are required for its use. Primarily, it provides an overview of the technologies and how they work together as well as some insight into the reasons behind the design of each component. It also gives instuctions for setting up and using the various libraries. Outside the scope of this documentation is reworking the system for individual situations.

1.3. About This Document's Audience

This documentation is aimed at developers who want to secure RESTful web services using PressGang Belay. It is assumed that these developers have, or are planning to build a system that they would like to integrate the libraries with. It is also assumed that the readers have had some experience with the technologies that are utilized by PressGang Belay, such as Maven and GWT. There will not be any coverage of the inner workings of these technologies.

1.4. About PressGang Belay's Technologies

Core technologies used in the PressGang Belay projects include Java EE, JBoss and GWT. The OAuth2 Auth Server Provider, OAuth2 Resource Server Provider and OpenID Provider projects have been tested on JBoss Application Server 7 with OpenJDK7; they are not designed or guaranteed to run on any other platform at present. These projects have been tested with the RESTEasy implementation of JAX-RS that is provided by JBoss. The OAuth2 GWT Client Provider is, naturally, designed for use with GWT. All of the projects have been built with Maven. The key libraries used are Apache Amber, OpenID-Filter and GWT-OAuth2. As the Apache Amber and OpenID-Filter libraries have not had formal releases yet, their use may necessitate changes in these projects in the future. Likewise, while this project tries to follow the current OAuth2 specification (draft-ietf-oauth-v2-31) as closely as possible, as this is a draft, changes may prompt alterations in this project in the future.

1.5. PressGang Belay Components

A graphical representation of the various PressGang Belay components and how they interact.
Figure 1.1. PressGang Belay Components

1.6. About GWT

Google Web Toolkit (GWT) is an open source development toolkit for building and optimizing complex browser-based applications. The GWT SDK provides APIs and widgets which allow Java to be compiled into JavaScript.

1.7. About the GWT Client Application

The GWT Client Application is a sample app demonstrating use of the GWT Client Provider library. It shows how the library can be used to gain end-user authorization and call web services that are secured with OAuth2. This functionality is designed to work with any spec-compliant OAuth2 Authorization/Resource Server implementations. The sample application also demonstrates how the library can be used with the OAuth2 Auth Server and OAuth2 Resource Server implementations. It shows how to make an authorization request to the OAuth2 Auth Server, which will prompt end-users to authenticate via OpenID, and how to make subsequent requests for resources. The application also demonstrates the use of some user management services, such as querying the identity of the end-user and associating multiple OpenID identities with the same end-user.

1.8. About the GWT Client Provider

The GWT Client Provider is a library to assist with OAuth2 authorization and requests to secured resources. It is an extension of the GWT-OAuth2 library. It facilitates requests for end-user authorization and stores the OAuth2 access tokens and related information that is returned, either in the browser's local storage or in cookies. It provides a means of sending requests to OAuth2-secured web services with the required credentials, prompting the end-user to authenticate and authorize the request if necessary, and will store any changes to those credentials that are included with the response.

1.9. About the Authorization Server

The Authorization Server is a sample OAuth2 authorization server implementation that can be used by both the sample GWT Client Application and any apps utilizing the Resource Server Provider for authentication and authorization purposes. It allows client applications, such as the GWT Client Application, to authenticate users via an OpenID provider and will generate and return an OAuth2 access token and its expiry after this process is complete. For confidential clients, it will also return a refresh token. The Authorization Server also communicates with the Resource Server. When a user requests a particular resource from a REST interface protected by the Resource Server Provider, the Authorization Server will return information about the user's token when requested. The Authorization Server implementation is given as an example of how to use the Authorization Server Provider library to create an authorization server; developers can customize the implementation as they see fit.

1.10. About the Authorization Server Provider

The Authorization Server Provider is a library to assist with the creation of an OAuth2 Authorization Server. It uses the Apache Amber library. It offers a data model for end-users, client applications, scopes, token grants etc. It also provides implementations for OAuth2 auth and token endpoints, using OpenID as the authentication mechanism for end-users, as well as implementations for user-management tasks. There is also an implementation of authorization information endpoints designed for use with a resource server using the Resource Server Provider library. This authorization information could be shared via a database instead if desired; the default OAuth2RSAuthService used could be overridden to achieve this. All of these endpoint implementations can be replaced or ignored in an Authorization Server webapp.

1.11. PressGang Belay OAuth2 Auth Server Provider Entity Relationship Diagram

An entity relationship diagram for the Auth Server Provider's database.
Figure 1.2. PressGang Belay OAuth2 Auth Server Provider Entity Relationship Diagram

1.12. About the OpenID Provider

The OpenID Provider is a sample implementation of an OpenID authentication server. This can be used in place or in concert with third-party identity providers such as Google, Yahoo! or MyOpenID. The OAuth2 Authorization Server communicates with the OpenID Provider to authenticate end-users and request identity attributes. The sample OpenID Provider implementation could be used as an internal-only service, wrapping internal authentication methods with OpenID. The sample app uses form-based authentication, but any authentication method could be used.

1.13. About the OAuth2-secured REST App

The OAuth2-secured REST app is a sample application that demonstrates how the OAuth2 Resource Server Provider library can be used to secure RESTful web services. It is a basic REST application that provides endpoints using the GET, POST, PUT and DELETE methods. These endpoints are protected by OAuth2 using a filter; clients need to have a valid token issued by the OAuth2 Authorization Server to access them.

1.14. About Supported OAuth2 Authorization Flows

The OAuth2 specification defines four authorization grant types or flows: Authorization Code, Implicit, Resource Owner Password Credentials and Client Credentials. PressGang Belay provides support for the first two of these, the Authorization Code Flow and the Implicit Flow.

The Authorization Code Flow is only appropriate for client applications that can protect a client secret, such as web applications with a secure server-side. These are known as confidential clients. For some OAuth2 endpoints they are required to authenticate themselves using their client secret. In this flow, an authorization code is first granted to the client application, and then exchanged for an access token in a separate request. Refresh tokens are issued and can be used to obtain new access tokens.

The Implicit Flow is optimized for client applications implemented in a browser, such as GWT clients, which cannot securely store a client secret. These are public clients and no refresh tokens are issued to them. They receive access tokens directly, without the intermediate step of an authorization code. As no refresh tokens are issued, the PressGang Belay Authorization Server implementation can extend the expiry time of access tokens that have been issued to public clients. This occurs when a token is used to access a protected resource and is within a given threshold of expiry. If the token is not in use and reaches its expiry time, the client will be required to go through the authorization process again.

1.17. PressGang Belay Authenticate End-User - All Clients

A diagram depicting authentication for any clients.
Figure 1.5. PressGang Belay Public Client Flow Diagram

1.18. PressGang Belay Obtain End-User Authorization - Public Client

A diagram depicting how private end-users obtain authorization.
Figure 1.6. PressGang Belay Public Client Flow Diagram

1.19. PressGang Belay Obtain End-User Authorization - Confidential Client

A diagram depicting how a confidential client obtains authorization.
Figure 1.7. PressGang Belay Public Client Flow Diagram

1.20. PressGang Belay Request Protected Resource - Public Client

A diagram depicting how a public client would gain access to a protected resource.
Figure 1.8. PressGang Belay Public Client Flow Diagram

1.21. PressGang Belay Request Protected Resource - Confidential Client

A diagram depicting how a confidential client would gain access to a protected resource.
Figure 1.9. PressGang Belay Public Client Flow Diagram

1.22. About the Resource Server Provider Library

The Resource Server Provider library can be used to secure RESTful web services using OAuth2, in conjunction with an OAuth2 Authorization Server. While the Auth Server handles end-user authentication and authorization, this library contains the logic to make decisions on whether or not to grant access to a particular endpoint, to a particular client application with an end-user token. It uses the Apache Amber library. The Resource Server Provider offers a data model for RESTful endpoints and access scopes, which must match those of the Authorization Server. It makes requests to the Authorization Server to retrieve information to assist with its decision-making. If the OAuth2 Auth Server and Resource Server were running together, a shared database could perhaps be used instead, however, as these two servers are separate enitites in the OAuth2 specification and Apache Amber libraries, they are also assumed to be separate in this implementation.

1.23. PressGang Belay OAuth2 Resource Server Provider Entity Relationship Diagram

An entity relationship diagram for the Resource Server Provider's database.
Figure 1.10. PressGang Belay OAuth2 Resource Server Provider Entity Relationship Diagram

1.24. About PressGang Belay OAuth Tokens

The default OAuth2 token issuer provided by the OAuth2 Auth Server Provider library generates random strings; it does not hash any user information. It can be overridden if this is desired, as documented in the Authorization Server and Associated Processes section. The Resource Server Provider library's org.jboss.pressgang.belay.oauth2.resourceserver.service.OAuth2RSAuthService, interface can be implemented to add logic to check the hash against the returned information. The implementation will have to be annotated with @Alternative and listed under alternatives in beans.xml.

By default all access tokens expire. However, it may be desirable to issue a token that does not expire, for example, if a client application were an internal terminal app. Although there are no endpoints for this sort of token grant, the Token Grant data model includes the boolean attribute accessTokenExpires, which could manually be set to false in the database. The Resource Server Provider library will take this into account when making its access decisions.

Chapter 2. GWT Client Provider Library and Sample Application

2.1. Set up the GWT Client Provider Library

Procedure 2.1. Task
  1. Obtain the GWT Client Provider library jar file and add it to the classpath of your project. If you are using Maven, you can achieve this by adding the Sonatype OSS repository and GWT Client Provider dependency to your pom.xml as follows in the example below. If you are using any other build tool, download the appropriate jar file from the Maven repository and add it as a library.
    <project>
        ...
        <repositories>
            <repository>
                <id>oss-repo</id>
                <name>OSS repository</name>
                <url>https://oss.sonatype.org/content/groups/public/</url>
            </repository>
        </repositories>
        ...
        <dependencies>
            <dependency>
                <groupId>org.jboss.pressgang.belay</groupId>
                <artifactId>gwt-client-provider</artifactId>
                <version>${belay.version}</version>
            </dependency>
        </dependencies>
        ...
    </project>
    
  2. Add the library to your GWT application's Module.gwt.xml file using the following code:
    <inherits name="org.jboss.pressgang.belay.oauth2.gwt.OAuth2GwtClientProvider"/>

Result
The GWT Client Provider Library is ready to be used by your application.

2.2. Authorize an End-user with the GWT Client Provider Library

Procedure 2.2. Task
  1. Declare and instantiate an OAuthHandler in your application using the following code:
    import org.jboss.pressgang.belay.oauth2.gwt.client.OAuthHandler;
    
    public class App implements EntryPoint {         
    
        private static final OAuthHandler AUTH_HANDLER = OAuthHandler.get();
    
    }
    
  2. Using this handler, you can authorize an end-user, using an OpenID Provider. To do this, you require:
    • The auth URL of your OAuth2 Authorization Server implementation.
    • The client ID of your application, as defined by your OAuth2 Authorization Server implementation.
    • The URL or domain name of the OpenID provider to use for end-user authentication.
    • The names of the access scopes to request.

    Where the auth URL is https://mydomain:443/MyAuthServer/rest/auth/login, the OpenID provider domain is gmail.com, the client ID is appClientId and the scope required is PERFORM_USER_MANAGEMENT, the code will be as follows:
    
    final AuthorizationRequest request = RequestUtil.openIdAuthorizationRequest("https://mydomain:443
      /MyAuthServer/rest/auth/authorize", "appClientId", 
      "gmail.com").withScopes("PERFORM_USER_MANAGEMENT");
    AUTH_HANDLER.sendAuthRequest(request, new Callback<String, Throwable>() {
    
        @Override
        public void onSuccess(String result) {
        	// Do something
        }
    
        @Override
        public void onFailure(Throwable caught) {
            // Handle error
        }
    });
    

Result
On success, the end-user is authorized, their credentials are stored in-browser and an OAuth2 access token is returned to the callback as the result.

2.3. Make a Request to a Resource Server

The OAuthHandler can be used to make requests to an OAuth2-secured Resource Server.
Procedure 2.3. Task
  • To make a request to a Resource Server, you need to construct an OAuthRequest. The constructor parameters required are:
    • The REST method type.
    • The URL to request.

    Optionally, the request headers, timeout and/or request data can be set, the same as with a GWT RequestBuilder.

    Here is an example of a basic GET request:
    
    AUTH_HANDLER.sendRequest(new OAuthRequest(RequestBuilder.GET, "https://mydomain:443
      /MyResourceServer/rest/resource"), new RequestCallback() {
                 
        @Override
        public void onResponseReceived(Request request, Response response) {
        	// Do something
        }
    
        @Override
        public void onError(Request request, Throwable exception) {
            // Handle error
        }
    });
    

Result
A request to the Resource Server has been created using the required parameters.

2.4. Retrieve End-user Data

If the Belay Auth Server implementation is in use, you can query the identity and user information endpoints for data about the currently authorized user and their primary OpenID identity.
Procedure 2.4. Task
  • To make a request for user information, for example, use the following code as a template:
    
    AUTH_HANDLER.sendRequest(new OAuthRequest(RequestBuilder.GET, "https://mydomain:443
      /MyAuthServer/rest/auth/user/queryUser"), new RequestCallback() {
    
        @Override
        public void onResponseReceived(Request request, Response response) {
        	// Do something
        }
     
        @Override
        public void onError(Request request, Throwable exception) {
            // Handle error
        }
    });
    

Result
A request for information about the currently authorized user is sent and JSON data returned.

2.5. Associate End-user Identities

An end-user may wish to use multiple OpenID identities to authenticate themselves. The Belay Authorization Server implementation provides an endpoint to associate two end-users and their identities, merging them into one end-user.
Procedure 2.5. Task
  • The RequestUtil class includes helper methods to assist with the creation of an appropriate OAuthRequest for end-user identity association, and the designation of an end-user's primary identity. Here is an example of adding a second identity to an end-user. The second identity must be authorized before the associate request can be made, and the authorization from the first identity must be recorded, as both identities need to be authorized by the Authorization Server in order to be associated. AUTH_HANDLER.getLastTokenResult() is used to retrieve the access token of the first identity before the second identity is authorized (as a forced request) and overwrites this information (as the client application is the same for both). If either identity were already associated with other identities, the entire identity group would end up associated with the same end-user. The parameters used are:
    • The HTTP method of the association endpoint.
    • The association URL.
    • The application's unique client ID.
    • A current access token for the end-user to associate.
    • Whether or not the new identity should be the resulting user's primary identity.

    
    final String originalToken = AUTH_HANDLER.getLastTokenResult();
    final AuthorizationRequest authRequest = 
      RequestUtil.openIdAuthorizationRequest("https://mydomain:443
      /MyAuthServer/rest/auth/authorize", "appClientId", "http://username.myopenid.com")
                                                        .withScopes(PERFORM_USER_MANAGEMENT)
                                                        .forceNewRequest(true);
    AUTH_HANDLER.sendAuthRequest(authRequest, new Callback<String, Throwable>() {
        @Override
        public void onSuccess(String result) {
            final OAuthRequest request = RequestUtil.associateIdentitiesRequest(
              RequestBuilder.POST, 
              "https://mydomain:443/MyAuthServer/rest/auth/user/associate", 
              "appClientId",
              originalToken, 
              false);
            AUTH_HANDLER.sendRequest(request, new RequestCallback() {
    
                @Override
                public void onResponseReceived(Request request, Response response) {
                    // Do something
                }
    
                @Override
                public void onError(Request request, Throwable exception) {
                    // Handle error
                }
            });
        }
    
        @Override
        public void onFailure(Throwable caught) {
            // Handle error
        }
    });
    

Result
The end-user identities are associated.

2.6. Change End-user's Primary Identity

Every end-user must have a primary identity out of those identities associated with them. The primary identity can be changed.
Procedure 2.6. Task
  • The RequestUtil class includes a helper method to create an OAuthRequest to change an end-user's primary identity. The end-user must be authorized before this request is made, and the identity specified must be associated with the end-user. Here is an example. The parameters used are:
    • The HTTP method of the endpoint to make an identity primary.
    • The URL of the endpoint to make an identity primary.
    • The identifier to make primary.

    
    AUTH_HANDLER.sendRequest(RequestUtil.makeIdentityPrimaryRequest(RequestBuilder.GET, 
      "https://mydomain:443/MyAuthServer/rest/auth/user/makeIdentityPrimary", 
      "http://username.myopenid.com"), new RequestCallback() {
        @Override
        public void onResponseReceived(Request request, Response response) {
            // Do something
        }
    
        @Override
        public void onError(Request request, Throwable exception) {
            // Handle error
        }
    });
    

Result
The identity associated with the identifier specified is now the end-user's primary identity.

2.7. Clear Stored Tokens

To force an end-user to reauthorize, you can clear the tokens stored in the browser. You may wish to clear token information stored locally when a user clicks a logout button, for example. You should also invalidate current tokens with the Authorization Server so they cannot be used by anyone else.
Procedure 2.7. Task
  • To clear stored tokens, use the OAuthHandler as follows :
    AUTH_HANDLER.clearAllTokens();
    

Result
Tokens that had been stored are cleared.

2.8. Invalidate Token Grant

The Belay Authorization Server implementation provides an endpoint for requests to invalidate a token grant so it can no longer be used to access resources. You may wish to invalidate a token grant when a user clicks a logout button, for example. You may also wish to clear the locally stored tokens at this time so no attempt is made to use the invalidated token.
Procedure 2.8. Task
  • To invalidate a token grant, make a request to the invalidate endpoint as follows:
    AUTH_HANDLER.sendRequest(RequestUtil.invalidateTokenGrantRequest(RequestBuilder.GET, 
      "https://mydomain:443/MyAuthServer/rest/auth/invalidate", 
      "appClientId"), new RequestCallback() {
        @Override
        public void onResponseReceived(Request request, Response response) {
            // Do something
        }
    
        @Override
        public void onError(Request request, Throwable exception) {
            // Handle error
        }
    });
    

Result
Token grant is invalidated and can no longer be used to access resources.

2.9. Retrieve Access Tokens

The GWT Client Provider library can be used to retrieve the last access token supplied or to retrieve a token for a specific request previously issued.
Procedure 2.9. Task
  • To retreive access tokens, use the following code:
    String accessToken = AUTH_HANDLER.getLastTokenResult();
    String accessTokenForSpecificRequest = 
      AUTH_HANDLER.getTokenForRequest(myStoredAuthRequest);
    

Result
The access token has been successfully retrieved.

2.10. Encode a URL

Procedure 2.10. Task
  • To encode a URL, use the following code:
    AUTH_HANDLER.encodeUrl("http://myurl");
    

Result
The specified URL has been encoded.

2.11. Prepare the GWT Client Application for Use

The GWT Client Application demonstrates how the GWT Client Provider library can be used and how a GWT client application can interact with the other components of PressGang Belay. To run the application:
Procedure 2.11. Task
  1. Navigate to the Belay GitHub page and clone the repository.
  2. Navigating to your local installation of a JBoss Application Server 7.X. Make sure your instance has SSL enabled.

    Add a username and password to the ApplicationRealm with the role guest, for use by the OpenID Provider.

    Add usernames and passwords for the authserver and resourceserver in the ApplicationRealm, with the role clientapp. Make sure these credentials are reflected in the resoureserver.properties files in the AuthServer and SecuredRestApp projects.

    Check that your JBoss instance has the jar file httpclient-4.1.1.jar in /modules/org/apache/httpcomponents/main, and that it is listed in the module.xml. Bugs may arise if this file is not present.

    Start your local instance of JBoss Application Server 7.X.
  3. In a terminal, enter the command mvn clean install -DskipTests to build the projects. To deploy the various war files to your JBoss instance, use the command mvn package jboss-as:deploy. You will need to deploy the OpenIdProvider, OAuth2AuthServer, OAuth2SecuredRestApp and OAuth2GwtClientApp projects for all aspects of the GWT Client Application demonstration to function.
  4. In a browser, navigate to https://localhost:8443/OAuth2GwtClientApp to try the demo application (replace 8443 with the port number your JBoss instance is using for SSL if necessary).
  5. If you wish to run the GwtClientApp functional tests, edit the functionaltest.properties file in OAuth2GwtClientApp/src/test/resources/functional and add the usernames and passwords of your external OpenID accounts for Google, Yahoo, Fedora etc. Alternatively, you can add these details as arguments when you run mvn using the parameter values in the functionaltest.properties file: ie: mvn clean install -Dgoogle.user=myid@gmail.com -Dgoogle.pass=password.

Result
The GWT Client Application is now ready to run.

Chapter 3. Resource Server Provider and Sample Application

3.1. Secure RESTful Web Services with the Resource Server Provider Library

It is assumed that you are using Linux and have a Maven web application project already set up with JAX-RS endpoints. It also assumed you are deploying to JBoss AS 7. If you use a different build tool, OS or application server, adapt the steps to suit.

The first major component to configure is your data source. If you already have a database for your application, you can choose to add the resource server provider's data to it, or you can create a separate database for this information. The following steps assume you wish to keep the data sources separate, or do not already have a data source configured. If this is not the case, you can simply merge the following with your existing configuration and database.
Procedure 3.1. Task
  1. Obtain the Resource Server Provider library jar file and add it to the classpath of your project. If you are using Maven, you can achieve this by adding the OSS repository and Resource Server Provider dependency to your pom.xml as follows in the example below. If you are using any other build tool, download the appropriate jar file from the Maven repository and add it as a library.
    <project>
        ...
        <repositories>
            <repository>
                <id>oss-repo</id>
                <name>OSS repository</name>
                <url>https://oss.sonatype.org/content/groups/public/</url>
            </repository>
        </repositories>
        ...
        <dependencies>
            <dependency>
                <groupId>org.jboss.pressgang.belay</groupId>
                <artifactId>resource-server-provider</artifactId>
                <version>${belay.version}</version>
            </dependency>
        </dependencies>
        ...
    </project>
    
  2. In {project.basedir}/src/main/webapp/WEB-INF, create a datasource XML file for the resource server database, such as oauth2resourceserver-ds.xml. Take note of the JNDI name as it must be included under jta-data-source in your persistence.xml. Adding to your persistence.xml will be continued in later steps. Here is an example datasource configuration file for an in-memory database:
    <?xml version="1.0" encoding="UTF-8"?>
    <datasources xmlns="http://www.jboss.org/ironjacamar/schema" 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      xsi:schemaLocation="http://www.jboss.org/ironjacamar/schema 
      http://docs.jboss.org/ironjacamar/schema/datasources_1_0.xsd">
        <datasource jndi-name="java:jboss/datasources/OAuth2ResourceServerDS" 
          pool-name="oauth2resourceserver" enabled="true"use-java-context="true">
            <connection-url>
                jdbc:h2:mem:oauth2resourceserver;DB_CLOSE_ON_EXIT=FALSE
            </connection-url>
            <driver>h2</driver>
            <security>
                <user-name>sa</user-name>
                <password>sa</password>
            </security>
        </datasource>
    </datasources>
    
  3. While you are working in the directory {project.basedir}/src/main/webapp/WEB-INF, create a file there called beans.xml. Its content should be as follows:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://java.sun.com/xml/ns/javaee" 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      xsi:schemaLocation="va.sun.com/xml/ns/javaee 
      http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
    </beans>
    
  4. Create a persistence.xml file under ${project.basedir}/src/main/resources/META-INF, or open your existing one. Add a persistence unit for the data source you defined in step 2, making sure the JTA data source specified matches the JNDI name in your data source XML and that the Resource Server Provider model classes to be used (OAuth2RSScope and OAuth2RSEndpoint) are listed. Here is an example persistence.xml:
    <?xml version="1.0" encoding="UTF-8"?>
    <persistence version="2.0" 
      xmlns="http://java.sun.com/xml/ns/persistence" 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      xsi:schemaLocation="</br>  http://java.sun.com/xml/ns/persistence 
      http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
    	<persistence-unit name="oauth2-resourceserver">
        	<jta-data-source>java:jboss/datasources/OAuth2ResourceServerDS</jta-data-source>
            <jar-file>resource-server-provider-1.0-SNAPSHOT.jar</jar-file>
            <class>
                org.jboss.pressgang.belay.oauth2.resourceserver.data.model.OAuth2RSScope
            </class>
            <class>
                org.jboss.pressgang.belay.oauth2.resourceserver.data.model.OAuth2RSEndpoint
            </class>
            <!-- Demo database settings only. Not suitable for production environment -->
            <properties>
                <property name="jboss.entity.manager.factory.jndi.name"
                  value="java:app/OAuth2ResourceServerManagerFactory" />
                <property name="hibernate.hbm2ddl.auto" value="create-drop" />
                <property name="hibernate.hbm2ddl.import_files"
                  value="resourceserver-import.sql" />
                <property name="hibernate.show_sql" value="false" />
            </properties>
        </persistence-unit>
    </persistence>
    
  5. In the same directory, ${project.basedir}/src/main/resources/META-INF, create a file called resourceserver.properties. This file must be present with all properties set -- other than tokenExpiryExtensionThreshold, which is optional -- in order for the Resource Server Provider library to function. Here is an example resourceserver.properties file with comments explaining each property:
    authServerUsername=resourceserver #Basic auth username for the Resource Server, as set on the Auth Server. This is used when the library needs to request information about an OAuth token
    
    authServerPassword=password #Basic auth password for the Resource Server, as set on the Auth Server
    
    authServerInfoUrl=https://localhost:8443/OAuth2AuthServer/rest/auth/info #The endpoint the Resource Server Provider should query for OAuth2 token information
    
    entityManagerFactoryJndiAddress=java:app/OAuth2ResourceServerManagerFactory #The JNDI address of the Resource Server manager factory, as specified in your persistence.xml (see step 4)
    
    tokenExpiryExtensionThreshold=300 # If a token used by a public client (which can't access refresh tokens) is within this many seconds of expiring when a request is made, the expiry time will be extended. Defaults to 900 (15 minutes)
    
  6. The Resource Server Provider library needs to know what endpoints the Resource Server provides, and which scopes grant access to a particular endpoint. Endpoints are defined by their URL pattern, which can be a Java regular expression (see http://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html), and their HTTP method. If the endpoint URL should be treated as regex, the URL_REGEX boolean should be set to true. If the HTTP Method is null for a given URL pattern it will match all methods. The scope names used must match those used by the Auth Server, as it is the Auth Server that grants client access to particular scopes on behalf of end-users. If a token has any of the scopes mapped to an endpoint, requests made with that token will be granted access to the endpoint. The endpoints, scopes and mappings between them is information that needs to be imported into the database. Here is a sample resourceserver-import.sql file, placed in ${project.basedir}/src/main/resources to import data to a data source when the application is deployed. Using this sample data, only GET requests are allowed under the DEFAULT scope.
    
    insert into RS_SCOPE (SCOPE_ID, SCOPE_NAME) values (-1, 'DEFAULT')
    
    insert into RS_ENDPOINT (ENDPOINT_ID, ENDPOINT_URL, ENDPOINT_METHOD, URL_REGEX)
      values (-1, 'https://localhost:8443/OAuth2SecuredRestApp/rest/people', 'GET', false)
    
    insert into RS_ENDPOINT (ENDPOINT_ID, ENDPOINT_URL, ENDPOINT_METHOD, URL_REGEX)
      values (-2, 'https://localhost:8443/OAuth2SecuredRestApp/rest/people/[0-9]+', 'GET', 
      true)
    
    insert into RS_ENDPOINT (ENDPOINT_ID, ENDPOINT_URL, ENDPOINT_METHOD, URL_REGEX)
      values (-3, 'https://localhost:8443/OAuth2SecuredRestApp/rest/people', 'POST', false)
    
    insert into RS_ENDPOINT (ENDPOINT_ID, ENDPOINT_URL, ENDPOINT_METHOD, URL_REGEX)
      values (-4, 'https://localhost:8443/OAuth2SecuredRestApp/rest/people', 'PUT', false)
    
    insert into RS_ENDPOINT (ENDPOINT_ID, ENDPOINT_URL, ENDPOINT_METHOD, URL_REGEX)
      values (-5, 'https://localhost:8443/OAuth2SecuredRestApp/rest/people/[0-9]+', 
      'DELETE', true)
    
    insert into RS_SCOPE_RS_ENDPOINT (SCOPE_ID, ENDPOINT_ID) values (-1, -1)
    
    insert into RS_SCOPE_RS_ENDPOINT (SCOPE_ID, ENDPOINT_ID) values (-1, -2)
    
  7. The last major part of configuring a Resource Server using the Resource Server Provider library is to add a filter for the protected resources. This is done in the web.xml file. Create a file called web.xml under ${project.basedir}/src/main/webapp/WEB-INF, or open your existing file. You need to add a filter using the org.jboss.pressgang.belay.oauth2.resourceserver.filter.OAuth2RSFilter class and a mapping indicating which URLs should be protected by this filter. You also need to define a context parameter to tell the library which class to use to make the access decisions. Here is an example web.xml that secures all endpoints under and including /rest/people:
    <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
      http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
        <display-name>PressGang Belay OAuth2-secured App Example</display-name>
        <filter>
            <filter-name>OAuth2 Filter</filter-name>
            <filter-class>
                org.jboss.pressgang.belay.oauth2.resourceserver.filter.OAuth2RSFilter
            </filter-class>
        </filter>
        <filter-mapping>
            <filter-name>OAuth2 Filter</filter-name>
            <url-pattern>/rest/people/*</url-pattern>
        </filter-mapping>
        <context-param>
            <param-name>oauth.rs.provider-class</param-name>
            <param-value>
                org.jboss.pressgang.belay.oauth2.resourceserver.filter.OAuth2RSProvider
            </param-value>
        </context-param>
    </web-app>
    

Result
The Resource Server's endpoints are protected and use the Resource Server Provider Library for access decisions.

Chapter 4. Authorization Server and Associated Processes

4.1. Set Up an OAuth2 Authorization Server Using the Auth Server Provider Library

This task assumes you are using a Maven project structure on Linux and will be running your webapp on JBoss AS 7. If you use a different build tool, application server or OS, adapt the steps to suit.
Procedure 4.1. Task
  1. Obtain the Auth Server Provider library jar file and add it to the classpath of your project. If you are using Maven, you can achieve this by adding the OSS repository and Auth Server Provider dependency to your pom.xml as follows in the example below. If you are using any other build tool, download the appropriate jar file from the Maven repository and add it as a library.
    <project>
        ...
        <repositories>
            <repository>
                <id>oss-repo</id>
                <name>OSS repository</name>
                <url>https://oss.sonatype.org/content/groups/public/</url>
            </repository>
        </repositories>
        ...
        <dependencies>
            <dependency>
                <groupId>org.jboss.pressgang.belay</groupId>
                <artifactId>auth-server-provider</artifactId>
                <version>${belay.version}</version>
            </dependency>
        </dependencies>
        ...
    </project>
    
  2. Create a package under {project.basedir}/src/main/java in which to keep your web service code. Alternatively, you can define your endpoint paths in your web.xml. This documentation does not discuss this approach. To use the Java EE 6 no-XML approach to activating JAX-RS, in this package, create a class called JaxRsActivator that looks like the following, using your desired web service endpoint base in the @ApplicationPath annotation:
    import javax.ws.rs.ApplicationPath;
    import javax.ws.rs.core.Application;
    
    @ApplicationPath("/rest")
    public class JaxRsActivator extends Application {
       /* class body intentionally left blank */
    }
    
  3. The Auth Server Provider library uses the Belay Resource Server Provider library. As such, there are properties files for both libraries for custom configuration. Create a file called resourceserver.properties in the directory ${project.basedir}/src/main/resources/META-INF/. This file must be present with the first four properties set if you wish to use the Auth Server endpoint implementations provided by the Auth Server Provider library; the token expiry threshold property is optional. Here is an example resourceserver.properties file with comments explaining each property:
    authServerUsername=authserver #Basic auth username for the Auth Server, as set on your server. This is used when the Resource Server Provider library needs to request information about an OAuth token used to access an OAuth2-protected Auth Server endpoint, such as /rest/auth/identity/query
    
    authServerPassword=password #Basic auth password for the Auth Server, as set on your server
    
    authServerInfoUrl=https://localhost:8443/OAuth2AuthServer/rest/auth/info #The endpoint the Resource Server Provider should query for OAuth2 token information
    
    entityManagerFactoryJndiAddress=java:app/OAuth2AuthServerManagerFactory #The JNDI address of the Auth Server manager factory, as specified in your persistence.xml (see step 8)
    
    tokenExpiryExtensionThreshold=300 #If a token used by a public client (which can't access refresh tokens) is within this many seconds of expiring when a request is made, the expiry time will be extended. Defaults to 900 (15 minutes)
    
  4. In {project.basedir}/src/main/resource/META-INF you should also create a persistence.xml file. The important things to include are:
    • A reference to the Resource Server Provider jar file, as you will be using its model classes, and a listing of those classes
    • A reference to the Auth Server Provider jar file, as you will be using its model classes, and a listing of those classes
    • The property jboss.entity.manager.factory.jndi.name, which should be set to the same JNDI address you set in your resourceserver.properties file for the entityManagerFactoryJndiAddress property. This allows the Resource Server Provider to create an appropriate Entity Manager. The persistence unit name must be oauth2-authserver.

    Here is an example persistence.xml:
    <?xml version="1.0" encoding="UTF-8"?>
    <persistence version="2.0"
      xmlns="http://java.sun.com/xml/ns/persistence"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="
      http://java.sun.com/xml/ns/persistence
      http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
        <persistence-unit name="oauth2-authserver">
        	<jta-data-source>java:jboss/datasources/OAuth2AuthServerDS</jta-data-source>
            <jar-file>resource-server-provider-1.0.jar</jar-file>
            <jar-file>auth-server-provider-1.0.jar</jar-file>
            <class>
                org.jboss.pressgang.belay.oauth2.resourceserver.data.model.OAuth2RSScope
            </class>
            <class>
                org.jboss.pressgang.belay.oauth2.resourceserver.data.model.OAuth2RSEndpoint
            </class>
            <class>
                org.jboss.pressgang.belay.oauth2.authserver.data.model.ClientApplication
            </class>
            <class>
                org.jboss.pressgang.belay.oauth2.authserver.data.model.ClientApproval
            </class>
            <class>
                org.jboss.pressgang.belay.oauth2.authserver.data.model.Identity
            </class>
            <class>
                org.jboss.pressgang.belay.oauth2.authserver.data.model.OpenIdProvider
            </class>
            <class>
                org.jboss.pressgang.belay.oauth2.authserver.data.model.Scope
            </class>
            <class>
                org.jboss.pressgang.belay.oauth2.authserver.data.model.TokenGrant
            </class>
            <class>
                org.jboss.pressgang.belay.oauth2.authserver.data.model.CodeGrant
            </class>
            <class>
                org.jboss.pressgang.belay.oauth2.authserver.data.model.User
            </class>
            <!-- Demo database settings only. Not suitable for production environment -->
            <properties>
                <property name="jboss.entity.manager.factory.jndi.name"
                  value="java:app/OAuth2AuthServerManagerFactory" />
                <property name="hibernate.hbm2ddl.auto" value="create-drop" />
                <property name="hibernate.show_sql" value="false" />
            </properties>
        </persistence-unit>
    </persistence>
    
  5. If you are simply testing the system with an in-memory database, you will want to create an import.sql file in ${project.basedir}/src/main/resources to put some data in your database when the Auth Server starts. Whether you are using an in-memory database or a file database, you will need to make sure your database contains the same sort of information as included in the following sample import.sql. The data to import includes:
    • The Clients authorized to use the Auth Server, including their unique identifier, name and the redirect URI they use.
    • The OpenID providers available for end-user authentication, including their name and URL, either in full or just the domain if appropriate. OpenID providers that include a user ID as part their domains (ie: MyOpenID) should be recorded with the static part of the domain only.
    • The scopes that the Auth Server can assign to end-user identities, which must have unique names. There must be a default scope (as defined in the authserver.properties file) as this is the scope all end-users are allocated when they are first created.
    • The scopes that the Resource Server Provider uses when it is protecting Auth Server endpoints, such as the user management endpoints. These names should match the scope names used in the SCOPE table as it is the Auth Server that assigns these to end-users.
    • The Auth Server endpoints that the Resource Server Provider is being used to protect. Each endpoint must have a URL, which can be in the form of a Java regular expression, an HTTP method, and a boolean value specifying whether the URL should be treated as a regular expression or not.
    • The mapping between Resource Server scopes and Resource Server endpoints, ie: which scopes a user must have to access an endpoint.

    Here is a sample import.sql file. Note that this data allows clients to perform user management by default; you may wish to put these endpoints under a separate scope:
    insert into CLIENT (CLIENT_ID, CLIENT_IDENTIFIER, CLIENT_NAME, CLIENT_REDIRECT_URI, 
      GRANTS_MUST_EXPIRE) values (-1, 'pressgang_belay_id', 'GwtOAuth2Client', true, 
      'https://localhost:8443/OAuth2GwtClientApp/org.jboss.pressgang.belay.oauth2.gwt
      .sample.App/oAuthWindow.html')
    
    insert into OPENID_PROVIDER (PROVIDER_ID, PROVIDER_NAME, PROVIDER_URL) values (-1, 
      'Google', 'gmail.com')
    insert into OPENID_PROVIDER (PROVIDER_ID, PROVIDER_NAME, PROVIDER_URL) values (-2, 
      'BelayOpenID', 'https://localhost:8443/OpenIdProvider')
    insert into OPENID_PROVIDER (PROVIDER_ID, PROVIDER_NAME, PROVIDER_URL) values (-3, 
      'Yahoo', 'me.yahoo.com')
    insert into OPENID_PROVIDER (PROVIDER_ID, PROVIDER_NAME, PROVIDER_URL) values (-4, 
      'Facebook', 'facebook.com')
    insert into OPENID_PROVIDER (PROVIDER_ID, PROVIDER_NAME, PROVIDER_URL) values (-5, 
      'myOpenID', 'myopenid.com')
    insert into OPENID_PROVIDER (PROVIDER_ID, PROVIDER_NAME, PROVIDER_URL) values (-6, 
      'Fedora Account System','admin.fedoraproject.org')
    
    insert into SCOPE (SCOPE_ID, SCOPE_NAME) values (-1, 'DEFAULT')
    
    insert into RS_SCOPE (SCOPE_ID, SCOPE_NAME) values (-1, 'DEFAULT')
    
    insert into RS_ENDPOINT (ENDPOINT_ID, ENDPOINT_URL, ENDPOINT_METHOD, URL_REGEX) 
      values (-1, 'https://localhost:8443/OAuth2AuthServer/rest/auth/user/associate',
      'POST', false)
    insert into RS_ENDPOINT (ENDPOINT_ID, ENDPOINT_URL, ENDPOINT_METHOD, URL_REGEX)
      values (-2, 'https://localhost:8443/OAuth2AuthServer/rest/auth/user/makeIdentityPrimary',
      'GET', false)
    insert into RS_ENDPOINT (ENDPOINT_ID, ENDPOINT_URL, ENDPOINT_METHOD, URL_REGEX)
      values (-3, 'https://localhost:8443/OAuth2AuthServer/rest/auth/user/queryIdentity',
      'GET, false')
    insert into RS_ENDPOINT (ENDPOINT_ID, ENDPOINT_URL, ENDPOINT_METHOD, URL_REGEX)
      values (-4, 'https://localhost:8443/OAuth2AuthServer/rest/auth/user/queryUser',
      'GET', false)
    insert into RS_ENDPOINT (ENDPOINT_ID, ENDPOINT_URL, ENDPOINT_METHOD, URL_REGEX)
      values (-5, 'https://localhost:8443/OAuth2AuthServer/rest/auth/invalidate',
      'GET', false)
    
    insert into RS_SCOPE_RS_ENDPOINT (SCOPE_ID, ENDPOINT_ID) values (-2, -1)
    insert into RS_SCOPE_RS_ENDPOINT (SCOPE_ID, ENDPOINT_ID) values (-2, -2)
    insert into RS_SCOPE_RS_ENDPOINT (SCOPE_ID, ENDPOINT_ID) values (-2, -3)
    insert into RS_SCOPE_RS_ENDPOINT (SCOPE_ID, ENDPOINT_ID) values (-2, -4)
    insert into RS_SCOPE_RS_ENDPOINT (SCOPE_ID, ENDPOINT_ID) values (-1, -5)
    
  6. Create or navigate to the directory {project.basedir}/src/main/webapp/WEB-INF. In this directory, create a file called beans.xml. Its content should be as follows:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://java.sun.com/xml/ns/javaee" 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      xsi:schemaLocation="
      http://java.sun.com/xml/ns/javaee 
      http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
    </beans>
    
  7. In {project.basedir}/src/main/webapp/WEB-INF, create a datasource xml file for your database, such as oauth2authserver-ds.xml. Its JNDI name must match the jta-data-source included in your persistence.xml. Here is an example datasource configuration file for an in-memory database:
    <?xml version="1.0" encoding="UTF-8"?>
    <datasources xmlns="http://www.jboss.org/ironjacamar/schema"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.jboss.org/ironjacamar/schema 
      http://docs.jboss.org/ironjacamar/schema/datasources_1_0.xsd">
        <datasource jndi-name="java:jboss/datasources/OAuth2AuthServerDS"
          pool-name="oauth2authserver" enabled="true"
          use-java-context="true">
            <connection-url>
                jdbc:h2:mem:oauth2authserver;DB_CLOSE_ON_EXIT=FALSE
            </connection-url>
            <driver>h2</driver>
            <security>
                <user-name>sa</user-name>
                <password>sa</password>
            </security>
        </datasource>
    </datasources>
    
  8. In {project.basedir}/src/main/webapp/WEB-INF, create a web.xml file. There are several aspects of the Auth Server set-up to configure here. These are:
    • GuiceOverrideServletContextListener: The OpenID Filter library that the Auth Server uses is by default configured to use a Host Meta Fetcher that sends requests to Google as part of the OpenID provider discovery process. This may be undesirable if you are using a custom OpenID provider with an internal URL you don't wish to share, or for performance reasons. The GuiceOverrideServletContextListener overrides this behaviour and uses a default Host Meta Fetcher implementation that does not send requests to Google by default.
    • OpenID Filter: The OpenID filter must be configured for the OAuth2 auth endpoint that utilizes OpenID for end-user authentication.
    • OAuth Filter: The OAuth filter must be configured for the endpoints that have resources protected by OAuth2, such as the user management and token grant invalidation endpoints.
    • OAuth2 Context Parameters: Context params must be set to configure the OAuth2 libraries, which need to know which class to use as a resource server provider, what types of token transmission to accept (ie: query, header) and which endpoints to use for token requests and authorization requests.
    • Security Constraints: Basic security (or an alternative) needs to be set up for protected resource endpoints, such as the token endpoint for confidential clients.

    Here is a sample web.xml with all of these configured:
    <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
      http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    	<display-name>PressGang Belay OAuth2 Auth Server</display-name> 
    
    	<!-- Used to override Guice binding in the openid-filter library -->
    	<listener>
            <listener-class>
                org.jboss.pressgang.belay.oauth2.authserver.openid
                  .GuiceOverrideServletContextListener
            </listener-class>
        <listener>
    
    	<!-- The OpenID Filter handles identity authentication -->
        <filter>
            <filter-name>OpenID Filter</filter-name>
            <filter-class>com.google.code.openid.RelyingPartyFilter</filter-class>
        </filter>
    
    	<!-- This defines the URL that requires OpenID authentication -->
        <filter-mapping>
            <filter-name>OpenID Filter</filter-name>
            <url-pattern>/rest/auth/authorize</url-pattern>
        </filter-mapping>
    
        <filter>
            <filter-name>OAuth Filter</filter-name>
            <filter-class>
                oss.pressgang.belay.oauth2.resourceserver.filter.OAuth2RSFilter
            </filter-class>
        </filter>
    
        <filter-mapping>
            <filter-name>OAuth Filter</filter-name>
            <url-pattern>/rest/auth/user/*</url-pattern>
            <url-pattern>/rest/auth/invalidate</url-pattern>
        </filter-mapping>
    
        <context-param>
            <param-name>oauth.rs.provider-class</param-name>
            <param-value>
                org.jboss.pressgang.belay.oauth2.resourceserver.filter.OAuth2RSProvider
            </param-value>
        </context-param>
    
        <context-param>
            <param-name>oauth.provider.tokens.request</param-name>
            <param-value>/rest/auth/token</param-value>
        </context-param>
    
        <context-param>
            <param-name>oauth.provider.tokens.access</param-name>
            <param-value>/rest/auth/authorize</param-value>
        </context-param>
    
        <context-param>
            <param-name>oauth.rs.tokens</param-name>
            <param-value>HEADER</param-value>
        </context-param>
    
        <security-constraint>
            <web-resource-collection>
                <web-resource-name>ClientResources</web-resource-name>
                <url-pattern>/rest/auth/token</url-pattern>
                <url-pattern>/rest/auth/info</url-pattern>
            </web-resource-collection>
    
            <auth-constraint>
                <role-name>clientapp</role-name>
            </auth-constraint>
    
            <user-data-constraint>
                <transport-guarantee>CONFIDENTIAL</transport-guarantee>
            </user-data-constraint>
        </security-constraint>
    
        <login-config>
            <auth-method>BASIC</auth-method>
            <realm-name>ApplicationRealm</realm-name>
        </login-config>
    
        <security-role>
            <role-name>clientapp</role-name>
        </security-role>
    
    </web-app>
    

Result
An OAuth2 Authorization Server has been set up and configured for use with the Auth Server Provider Library.

4.2. Define Paths For Provided Endpoint Implementations

For the Auth Server to use any of the library implementations, you must define an endpoint path. For this example, the GrantEndpointImpl will be used, which implements the GrantEndpoint interface.
Procedure 4.2. Task
  1. Create a class extending your desired library implementation of the endpoint, for example, GrantEndpointImpl.
  2. Add the @Path and any relevant request annotations. For example:
    import org.jboss.pressgang.belay.oauth2.authserver.rest.impl.GrantEndpointImpl;
    
    import javax.enterprise.context.RequestScoped;
    import javax.ws.rs.Path:
     
    @RequestScoped
    @Path("/auth/invalidate")
    public class GrantWebService extends GrantEndpointImpl {
        /* class body intentionally left blank */
    }

Result
A path has been defined for a provided endpoint implementation.

4.3. Customize Paths For Provided Endpoint Implementations

If you wish to define custom paths for individual methods of an endpoint interface where these are predefined, such as the UserManagementEndpoint interface, you must override the methods and decorate them with all the required JAX-RS annotations as these will no longer be inherited. Otherwise, the paths defined in the interface will be used, with the base path you defined.
Procedure 4.3. Task
  • Use the following code as a template for your implementation:
    import org.apache.amber.oauth2.common.exception.OAuthProblemException;
    import org.apache.amber.oauth2.common.exception.OAuthSystemException;
    import org.jboss.pressgang.belay.oauth2.authserver.rest.impl.UserManagementEndpointImpl;
    import org.jboss.pressgang.belay.oauth2.shared.data.model.IdentityInfo;
    import org.jboss.pressgang.belay.oauth2.shared.data.model.UserInfo;
     
    import javax.enterprise.context.RequestScoped;
    import javax.servlet.http.HttpServletRequest;
    import javax.ws.rs.GET;
    import javax.ws.rs.Path;
    import javax.ws.rs.Produces;
    import javax.ws.rs.QueryParam;
    import javax.ws.rs.core.Context;
    import javax.ws.rs.core.MediaType;
    import javax.ws.rs.core.Response;
    import java.net.URISyntaxException;
     
    @RequestScoped
    @Path("/auth/user")
    public class UserManagementWebService extends UserManagementWebServiceImpl {
        @Override
        @GET
        @Produces(MediaType.APPLICATION_JSON)
        @Path("/myCustomQueryUserPath")
        public UserInfo getUserInfo(@Context HttpServletRequest request, String identifier) {
           	return super.getPrimaryUserInfo(request, identifier);
        }
    
        @Override
        @GET
        @Produces(MediaType.APPLICATION_JSON)
        @Path("/myCustomQueryIdentityPath")
        public IdentityInfo getIdentityInfo(@Context HttpServletRequest request, 
                                            @QueryParam("id") String identifier) {
            return super.getPrimaryIdentityInfo(request, identifier);
        }
    
        @Override
        @GET
        @Path("/myCustomMakeIdentityPrimaryPath")
        public Response makeIdentityPrimary(@Context HttpServletRequest request, 
                                            @QueryParam("id") String identifier) {
            return super.makeIdentityPrimary(request, identifier);
        }
    }

    Note

    If you wish to write your own implementations for some or all of the OAuth2 endpoints defined by the Auth Server Provider, you can implement the interfaces supplied (ie: TokenEndpoint, UserManagementEndpoint). You can then configure your Auth Server implementation to use your authorization and token endpoints in your web.xml. You should also inform your resource servers and OAuth2 clients where these endpoints are located.

Result
Predefined paths have been overridden and custom paths have been defined for individual methods of an endpoint interface.

4.4. Override Auth Server Provider Configuration Options

You may wish to create an authserver.properties file in ${project.basedir}/src/main/resources/META-INF/ to override Auth Server Provider configurations options. However, this file and every property in it is optional; defaults will be used if the file is not found or a property is not set.
Procedure 4.4. Task
  • Here is an example authserver.properties files showing the default values with comments explaining each property available:
    oAuthTokenExpiry=3600 #The expiry time of an OAuth2 access token in seconds, set when the token is created. This is also the time used to extend public client access tokens by when their expiry time is pushed out
    
    oAuthCodeExpiry=60 #The expiry time of an OAuth2 authorization code in seconds, set when the code is created
    
    urlEncoding=UTF-8 #The encoding type specified when encoding or decoding URLs
    
    openIdRealm=/OAuth2AuthServer/rest/auth/ #The OpenID realm of the Auth Server
    
    restEndpointBasePath=/OAuth2AuthServer/rest #The base path for the Auth Server's RESTful endpoints, as defined by the application name and JAX-RS base path
    
    authEndpoint=/auth/authorize #The path to the OAuth2 authorization endpoint, relative to the project's JAX-RS base path
    
    openIdReturnUri=/OAuth2AuthServer/rest/auth/authorize #The endpoint to use as the OpenID return URI, which should match the grantEndpoint property but be expressed relative to the server's domain
    
    defaultScopeName=DEFAULT #The name of the scope that all users should have upon creation and all token grants are given, capitalized by convention. This must have a matching definition in the database
    
    promptEndUserToApproveClientAppOnEveryLogin=false #Boolean true/false. True if you want the end-user to be prompted to approve client access of their auth info and resources on every login
    
    endUserConsentUri=/auth/consent #The URI to redirect end-users to give consent for client access to their auth info and resources, relative to the project's JAX-RS base path
    
    endUserConsentFormCssLocation= #The URL where a style sheet for the end-user consent page can be found; optional
    

Result
An authserver.properties file has been created and the default configuration options have been overriden.

4.5. Override Default OAuth2 Token Generation Service

The default OAuth2 token generation service from the Auth Server Provider library uses an MD5 token generator and does some checks to ensure active tokens are unique.
Procedure 4.5. Task
  1. If you wish to override this service, you can create your own implementation of the org.jboss.pressgang.belay.oauth2.authserver.service.TokenIssuer interface decorated with the javax.enterprise.inject.Alternative annotation using the following example code:
    import org.apache.amber.oauth2.common.exception.OAuthSystemException;
    import org.jboss.pressgang.belay.oauth2.authserver.service.TokenIssuer;
    import javax.ejb.Stateless;
    import javax.enterprise.inject.Alternative;
    
    @Alternative
    @Stateless
    public class AlternativeTokenIssuer implements TokenIssuer {
    
        @Override
        public String accessToken() throws OAuthSystemException {
            return "foo";
        }
    
        @Override
        public String refreshToken() throws OAuthSystemException {
            return "bar";
        }
    
        @Override
        public String authorizationCode() throws OAuthSystemException {
            return "foobar";
        }
    }
    
  2. Enable your implementation and override the default by adding your class to the Auth Server's beans.xml:
    <beans>
        ...
        <alternatives>
            <class>
                org.jboss.pressgang.belay.oauth2.authserver.sample
                  .service.AlternativeTokenIssuer
            </class>
        </alternatives>
    </beans>
    

Result
A custom Token Issuer implementation has been created and overrides the default OAuth2 token generation service.

4.6. Override Default Auth Service

The Belay Authorization Server implementation uses the AuthService type for all data access. If you wish to change the underlying data model and data access methods, you can provide an alternative implementation of this interface.
Procedure 4.6. Task
  1. If you wish to override the DefaultAuthService implementation, create your own implementation of the org.jboss.pressgang.belay.oauth2.authserver.service.AuthService interface decorated with the javax.enterprise.inject.Alternative annotation.
  2. Enable your implementation and override the default by adding your class to the Auth Server's beans.xml:
    <beans>
        ...
        <alternatives>
            <class>
                org.jboss.pressgang.belay.oauth2.authserver.sample
                  .service.AlternativeAuthService
            </class>
        </alternatives>
    </beans>
    

Result
A custom Auth Service implementation has been created and overrides the default implementation.

Revision History

Revision History
Revision 1.0-1Wed Nov 14 2012 CS Builder Robot
Built from Content Specification: 11411, Revision: 328326