A Simple OAuth2 Client and Server Example: Part II - No Fluff Just Stuff

A Simple OAuth2 Client and Server Example: Part II

Posted by: Jason Lee on July 12, 2013

In the last post, we took a look at the server side of our OAuth2 system. In this post, we’ll take a quick look at the unit tests that will act as TheUser.

pass::[more]

Let’s get right to the code:

@RunAsClient
      public class AuthTest extends Arquillian {
      
          @ArquillianResource
          private URL url;
          private Client client = JerseyClientBuilder.newClient();
      
          @Deployment
          public static WebArchive createDeployment() {
              WebArchive archive = ShrinkWrap.create(WebArchive.class)
                      .addPackages(true, "com.steeplesoft.oauth2")
                      .addAsWebInfResource(
                          new FileAsset(
                              new File("src/main/webapp/WEB-INF/beans.xml")),
                                  "beans.xml")
                      .addAsWebInfResource(
                          new FileAsset(
                              new File("src/main/webapp/WEB-INF/web.xml")),
                                  "web.xml")
                      .addAsLibraries(Maven.resolver()
                          .loadPomFromFile("pom.xml")
                          .importRuntimeDependencies()
                          .resolve()
                          .withTransitivity()
                          .asFile());
              return archive;
          }
      
          @Test
          public void authorizationRequest() {
              try {
                  Response response = makeAuthCodeRequest();
                  Assert.assertEquals(Status.OK.getStatusCode(),
                      response.getStatus());
      
                  String authCode = getAuthCode(response);
                  Assert.assertNotNull(authCode);
              } catch (OAuthSystemException |
                      URISyntaxException |
                      JSONException ex) {
                  Logger.getLogger(AuthTest.class.getName())
                      .log(Level.SEVERE, null, ex);
              }
          }
      
          @Test
          public void authCodeTokenRequest() throws OAuthSystemException {
              try {
                  Response response = makeAuthCodeRequest();
                  Assert.assertEquals(Status.OK.getStatusCode(),
                      response.getStatus());
      
                  String authCode = getAuthCode(response);
                  Assert.assertNotNull(authCode);
                  OAuthAccessTokenResponse oauthResponse =
                      makeTokenRequestWithAuthCode(authCode);
                  assertNotNull(oauthResponse.getAccessToken());
                  assertNotNull(oauthResponse.getExpiresIn());
              } catch (OAuthSystemException |
                      URISyntaxException |
                      JSONException |
                      OAuthProblemException ex) {
                  Logger.getLogger(AuthTest.class.getName())
                      .log(Level.SEVERE, null, ex);
              }
          }
      
          @Test
          public void directTokenRequest() {
              try {
                  OAuthClientRequest request = OAuthClientRequest
                          .tokenLocation(url.toString() + "api/token")
                          .setGrantType(GrantType.PASSWORD)
                          .setClientId(Common.CLIENT_ID)
                          .setClientSecret(Common.CLIENT_SECRET)
                          .setUsername(Common.USERNAME)
                          .setPassword(Common.PASSWORD)
                          .buildBodyMessage();
      
                  OAuthClient oAuthClient =
                      new OAuthClient(new URLConnectionClient());
                  OAuthAccessTokenResponse oauthResponse =
                      oAuthClient.accessToken(request);
                  assertNotNull(oauthResponse.getAccessToken());
                  assertNotNull(oauthResponse.getExpiresIn());
              } catch (OAuthSystemException |
                      OAuthProblemException ex ) {
                  Logger.getLogger(AuthTest.class.getName())
                      .log(Level.SEVERE, null, ex);
              }
          }
      
          @Test
          public void endToEndWithAuthCode() {
              try {
                  Response response = makeAuthCodeRequest();
                  Assert.assertEquals(Status.OK.getStatusCode(),
                      response.getStatus());
      
                  String authCode = getAuthCode(response);
                  Assert.assertNotNull(authCode);
      
                  OAuthAccessTokenResponse oauthResponse =
                      makeTokenRequestWithAuthCode(authCode);
                  String accessToken = oauthResponse.getAccessToken();
      
                  URL restUrl = new URL(url.toString() + "api/resource");
                  WebTarget target = client.target(restUrl.toURI());
                  String entity = target.request(MediaType.TEXT_HTML)
                          .header(Common.HEADER_AUTHORIZATION, "Bearer " +
                              accessToken)
                          .get(String.class);
                  System.out.println("Response = " + entity);
              } catch (MalformedURLException |
                      URISyntaxException |
                      OAuthProblemException |
                      OAuthSystemException |
                      JSONException ex) {
                  Logger.getLogger(AuthTest.class.getName())
                      .log(Level.SEVERE, null, ex);
              }
          }
      
          void testValidTokenResponse(HttpURLConnection httpURLConnection)
                  throws Exception {
              InputStream inputStream;
              if (httpURLConnection.getResponseCode() == 400) {
                  inputStream = httpURLConnection.getErrorStream();
              } else {
                  inputStream = httpURLConnection.getInputStream();
              }
              String responseBody = OAuthUtils.saveStreamAsString(inputStream);
              assert (Common.ACCESS_TOKEN_VALID.equals(responseBody));
          }
      
          private Response makeAuthCodeRequest() throws OAuthSystemException,
                  URISyntaxException {
              OAuthClientRequest request = OAuthClientRequest
                      .authorizationLocation(url.toString() + "api/authz")
                      .setClientId(Common.CLIENT_ID)
                      .setRedirectURI(url.toString() + "api/redirect")
                      .setResponseType(ResponseType.CODE.toString())
                      .setState("state")
                      .buildQueryMessage();
              WebTarget target = client.target(new URI(request.getLocationUri()));
              Response response = target.request(MediaType.TEXT_HTML).get();
              return response;
          }
      
          private String getAuthCode(Response response) throws JSONException {
              JSONObject obj = new JSONObject(response.readEntity(String.class));
              JSONObject qp = obj.getJSONObject("queryParameters");
              String authCode = null;
              if (qp != null) {
                  authCode = qp.getString("code");
              }
      
              return authCode;
          }
      
          private OAuthAccessTokenResponse
                  makeTokenRequestWithAuthCode(String authCode)
              throws OAuthProblemException, OAuthSystemException {
              OAuthClientRequest request = OAuthClientRequest
                      .tokenLocation(url.toString() + "api/token")
                      .setClientId(Common.CLIENT_ID)
                      .setClientSecret(Common.CLIENT_SECRET)
                      .setGrantType(GrantType.AUTHORIZATION_CODE)
                      .setCode(authCode)
                      .setRedirectURI(url.toString() + "api/redirect")
                      .buildBodyMessage();
              OAuthClient oAuthClient =
                  new OAuthClient(new URLConnectionClient());
              OAuthAccessTokenResponse oauthResponse =
                  oAuthClient.accessToken(request);
              return oauthResponse;
          }
      }

The first thing you should notice is that we’re using TestNG and Arquillian. I won’t go into the details on the Arquillian set up here, other than to note that we need our test to @RunAsClient, and to point out the @Deployment method that builds our test archive for us.

Moving on to authorizationRequest, we can see (in makeAuthCodeRequest) how the Oltu library makes it easy to build the request for an authorization code. Utlimately, the library helps use create the request URI, which we then pass to the JAX-RS client as it makes the actual request. To be honest, there’s a bit here (such as the state field) that I don’t understand. Any expert help here would be appreciated. :)

The next method, authCodeTokenRequest, shows the flow of getting an authorization code, then using it to get the access token. That’s followed by an example of a direct request for token via the password grant type. Finally, we have an end to end example, from authorization code to accessing our protected resource.

That’s all there is to it. As you can see in the POM and arquillian.xml, the only container currently supported is GlassFish, which the tests expect to find in glassfish4/ in the project’s base directory. Once that’s installed, the tests can be run with the normal mvn test.

If you have any questions about the code, I can try to answer them, but as should be clear by now, I’m still learning all of this. If I’ve made any mistakes in the code or my description of the protocol, please don’t be shy about correcting me. We’re all hear to learn. :)

Jason Lee

About Jason Lee

Jason Lee is a Senior Java Developer for Sun Microsystems working on the GlassFish Administration Console, and is a member of the JSF 2.0 (JSR 314) Expert Group. Jason has extensive experience working with web-based technologies such as JavaServer Faces and Ajax, as well as enterprise technologies based on the GlassFish platform. He is currently the main developer of Mojarra Scales, working to create a set of high quality JSF components wrapping libraries such as the Yahoo! User Interface Library, as well as bring Facelets compatibility to JSFTemplating.

Jason has been writing software professionally since 1997 in a wide variety of languages and environments, including Java, PHP, C/C++, and Delphi on both Linux/Unix and Windows. You can read more about what Jason's working on at his blog at http://blogs.steeplesoft.com

Apart from work, he is currently serving as the president of the Oklahoma City Java Users Group, where he is an active member and presenter. More importantly, Jason is married to a beautiful woman and has two sons who, thankfully, look like their mother.

Why Attend the NFJS Tour?

  • » Cutting-Edge Technologies
  • » Agile Practices
  • » Peer Exchange

Current Topics:

  • Languages on the JVM: Scala, Groovy, Clojure
  • Enterprise Java
  • Core Java, Java 8
  • Agility
  • Testing: Geb, Spock, Easyb
  • REST
  • NoSQL: MongoDB, Cassandra
  • Hadoop
  • Spring 4
  • Cloud
  • Automation Tools: Gradle, Git, Jenkins, Sonar
  • HTML5, CSS3, AngularJS, jQuery, Usability
  • Mobile Apps - iPhone and Android
  • More...
Learn More »