Fix conversion from AccessToken to OAuthToken

The login via UAA failed with "Server Error", when using the cfoauth
plugin with Gerrit stable-2.16, because OAuthToken-constructor provided
by the oauth extension of Gerrit does now require the 'secret'- and the
'raw'-parameter not to be null.

This change adds the raw response of the UAA server to the AccessToken
object, which is then handed to the OAuth extension point of Gerrit
instead of null.

Since UAA uses OAuth 2.0, no token secret is used. Since the Gerrit
OAuth extension point expects a token secret to be sent, an empty string
will be used instead. This follows the approach used by the scribe-java
library, which is used in the OAuth implementation of Gerrit and this
plugin.

Change-Id: I4e36b2a651951aff1cf08932b2902fa86905976e
diff --git a/src/main/java/com/googlesource/gerrit/plugins/cfoauth/AccessToken.java b/src/main/java/com/googlesource/gerrit/plugins/cfoauth/AccessToken.java
index 9ea32ed..56214d2 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/cfoauth/AccessToken.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/cfoauth/AccessToken.java
@@ -21,6 +21,7 @@
 
   private static final long serialVersionUID = 1L;
 
+  private final String raw;
   private final UserInfo userInfo;
   private final String value;
   private final long expiresAt;
@@ -31,26 +32,35 @@
   static final AccessToken UNDEFINED = new AccessToken();
 
   private AccessToken() {
-    this("", "", "", 0);
+    this("", "", "", 0, "");
   }
 
   /**
    * Creates an access token.
    *
-   * @param value the raw value of the access token.
+   * @param value the raw access token.
    * @param username the name of the token owner.
    * @param emailAddress the email address of the token owner.
    * @param expiresAt time to expiration of this tokens in seconds
    * since midnight January, 1st, 1970.
+   * @param raw the raw response body of the UAA server.
    */
   AccessToken(String value, String username, String emailAddress,
-      long expiresAt) {
+      long expiresAt, String raw) {
     if (value == null) {
       throw new IllegalArgumentException("token value must not be null");
     }
     this.userInfo = new UserInfo(username, emailAddress);
     this.value = value;
     this.expiresAt = expiresAt;
+    this.raw = raw;
+  }
+
+  /**
+   * Returns the raw response body from the UAA server.
+   */
+  public String getRaw() {
+	return raw;
   }
 
   /**
diff --git a/src/main/java/com/googlesource/gerrit/plugins/cfoauth/CFOAuthService.java b/src/main/java/com/googlesource/gerrit/plugins/cfoauth/CFOAuthService.java
index b5b294e..a3d2b01 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/cfoauth/CFOAuthService.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/cfoauth/CFOAuthService.java
@@ -38,6 +38,7 @@
 
   private static final String OAUTH_VERSION = "2.0";
   private static final String NAME = "Cloud Foundry UAA OAuth2";
+  private static final String EMPTY_STRING = "";
 
   private final UAAClient uaaClient;
   private final String providerId;
@@ -79,7 +80,8 @@
     if (token == null) {
       throw new UAAClientException("Must provide an access token");
     }
-    return getAsOAuthUserInfo(uaaClient.toAccessToken(token.getToken()));
+    return getAsOAuthUserInfo(uaaClient.toAccessToken(token.getToken(),
+      token.getRaw()));
   }
 
   @Override
@@ -104,7 +106,7 @@
           if (!uaaClient.verifyAccessToken(secret)) {
             throw new IOException("Authentication error");
           }
-          accessToken = uaaClient.toAccessToken(secret);
+          accessToken = uaaClient.toAccessToken(secret, EMPTY_STRING);
         } else {
           // "secret" is not an access token but likely a password;
           // send username and password to UAA and try to get an access
@@ -129,8 +131,12 @@
   }
 
   private OAuthToken getAsOAuthToken(AccessToken accessToken) {
-    return new OAuthToken(accessToken.getValue(), null, null,
-        accessToken.getExpiresAt() * 1000, providerId);
+    // The Gerrit OAuth extension point follows OAuth 1.0 and expects a token secret.
+    // OAuth 2.0, which is used by UAA, does not use token secrets anymore. Thus, an
+    // empty string is provided instead.
+    return new OAuthToken(accessToken.getValue(), EMPTY_STRING,
+        accessToken.getRaw(), accessToken.getExpiresAt() * 1000,
+        providerId);
   }
 
   private OAuthUserInfo getAsOAuthUserInfo(AccessToken accessToken) {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/cfoauth/UAAClient.java b/src/main/java/com/googlesource/gerrit/plugins/cfoauth/UAAClient.java
index fb67075..9ff9dbb 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/cfoauth/UAAClient.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/cfoauth/UAAClient.java
@@ -257,7 +257,7 @@
    * @throws UAAClientException if the given access token is not
    * valid or could not be converted into an <code>AccessToken</code>.
    */
-  public AccessToken toAccessToken(String accessToken)
+  public AccessToken toAccessToken(String accessToken, String rawResponse)
       throws UAAClientException {
     JsonObject jsonWebToken = toJsonWebToken(accessToken);
     long expiresAt = getLongAttribute(jsonWebToken, EXP_ATTRIBUTE, 0);
@@ -274,7 +274,8 @@
       throw new UAAClientException(
           "Invalid token: missing or invalid 'email' attribute");
     }
-    return new AccessToken(accessToken, username, emailAddress, expiresAt);
+    return new AccessToken(accessToken, username, emailAddress, expiresAt,
+      rawResponse);
   }
 
   /**
@@ -303,7 +304,7 @@
   @VisibleForTesting
   AccessToken parseAccessTokenResponse(String tokenResponse)
       throws UAAClientException {
-    return toAccessToken(getAccessTokenAttribute(tokenResponse));
+    return toAccessToken(getAccessTokenAttribute(tokenResponse), tokenResponse);
   }
 
   @VisibleForTesting
diff --git a/src/test/java/com/googlesource/gerrit/plugins/cfoauth/AccessTokenTest.java b/src/test/java/com/googlesource/gerrit/plugins/cfoauth/AccessTokenTest.java
index a9cf635..f728916 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/cfoauth/AccessTokenTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/cfoauth/AccessTokenTest.java
@@ -25,17 +25,21 @@
   private static final String TOKEN_VALUE = "tokenvalue";
   private static final String ANOTHER_TOKEN_VALUE = "anothertokenvalue";
   private static final long EXPIRES_AT = 4711L;
+  private static final String RAW_RESPONSE = "{"
+	      + "\"access_token\":\"" + TOKEN_VALUE + "\","
+	      + "\"token_type\":\"bearer\","
+	      + "\"expires_in\":3600}";
 
   private static final AccessToken TOKEN =
-      new AccessToken(TOKEN_VALUE, FOO, BAR, EXPIRES_AT);
+      new AccessToken(TOKEN_VALUE, FOO, BAR, EXPIRES_AT, RAW_RESPONSE);
   private static AccessToken TOKEN_DIFFERENT_VALUE =
-      new AccessToken(ANOTHER_TOKEN_VALUE, FOO, BAR, EXPIRES_AT);
+      new AccessToken(ANOTHER_TOKEN_VALUE, FOO, BAR, EXPIRES_AT, RAW_RESPONSE);
   private static AccessToken TOKEN_DIFFERENT_NAME =
-      new AccessToken(TOKEN_VALUE, ANOTHER_FOO, BAR, EXPIRES_AT);
+      new AccessToken(TOKEN_VALUE, ANOTHER_FOO, BAR, EXPIRES_AT, RAW_RESPONSE);
   private static AccessToken TOKEN_DIFFERENT_EMAIL =
-      new AccessToken(TOKEN_VALUE, FOO, ANOTHER_BAR, EXPIRES_AT);
+      new AccessToken(TOKEN_VALUE, FOO, ANOTHER_BAR, EXPIRES_AT, RAW_RESPONSE);
   private static final AccessToken TOKEN_DIFFERENT_EXPIRES =
-      new AccessToken(TOKEN_VALUE, FOO, BAR, EXPIRES_AT + 1);
+      new AccessToken(TOKEN_VALUE, FOO, BAR, EXPIRES_AT + 1, RAW_RESPONSE);
 
   @Test
   public void testCreateAccessToken() throws Exception {
@@ -52,7 +56,7 @@
   public void testExpiresAt() throws Exception {
     assertTrue(TOKEN.isExpired());
     assertFalse(new AccessToken(TOKEN_VALUE, FOO, BAR,
-        System.currentTimeMillis() + 10).isExpired());
+        System.currentTimeMillis() + 10, RAW_RESPONSE).isExpired());
   }
 
   @Test
@@ -71,7 +75,7 @@
 
   @Test(expected=IllegalArgumentException.class)
   public void testMissingValue() throws Exception {
-    new AccessToken(null, FOO, BAR, EXPIRES_AT);
+    new AccessToken(null, FOO, BAR, EXPIRES_AT, RAW_RESPONSE);
   }
 
   private void assertAccessToken(AccessToken accessToken, String username,
diff --git a/src/test/java/com/googlesource/gerrit/plugins/cfoauth/UAAClientTest.java b/src/test/java/com/googlesource/gerrit/plugins/cfoauth/UAAClientTest.java
index ab22c77..1d2ba1c 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/cfoauth/UAAClientTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/cfoauth/UAAClientTest.java
@@ -134,7 +134,8 @@
 
   @Test
   public void testGetAsAccessToken() throws Exception {
-    AccessToken accessToken = client.toAccessToken(HS256_TEST_TOKEN);
+    AccessToken accessToken = client.toAccessToken(HS256_TEST_TOKEN,
+        HS256_ACCESS_TOKEN_RESPONSE);
     assertHS266AccessToken(accessToken);
   }