You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by na...@apache.org on 2015/04/15 21:41:40 UTC

[35/39] jclouds git commit: * Refactor OAuth to be less complex. * Remove oauth as a standalone api. * Rename redundant OAuthAuthenticationFilter to OAuthFilter. * Make AuthorizationApi more simple by using form semantics. * Simplified OAuth by only

 * Refactor OAuth to be less complex.
 * Remove oauth as a standalone api.
 * Rename redundant OAuthAuthenticationFilter to OAuthFilter.
 * Make AuthorizationApi more simple by using form semantics.
 * Simplified OAuth by only permitting RS256 and none algos.


Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/46a7351a
Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/46a7351a
Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/46a7351a

Branch: refs/heads/master
Commit: 46a7351a8a2c38bc191a52d8f909976d37142cb8
Parents: a35d73c
Author: Adrian Cole <ac...@twitter.com>
Authored: Mon Nov 17 19:50:48 2014 -0800
Committer: Adrian Cole <ac...@twitter.com>
Committed: Tue Nov 18 10:43:33 2014 -0800

----------------------------------------------------------------------
 apis/oauth/pom.xml                              |   1 -
 .../org/jclouds/oauth/v2/AuthorizationApi.java  |  46 +++++++
 .../org/jclouds/oauth/v2/JWSAlgorithms.java     |  75 -----------
 .../java/org/jclouds/oauth/v2/OAuthApi.java     |  61 ---------
 .../org/jclouds/oauth/v2/OAuthApiMetadata.java  |  83 ------------
 .../jclouds/oauth/v2/binders/TokenBinder.java   |  77 ------------
 .../jclouds/oauth/v2/config/Authorization.java  |  30 +++++
 .../java/org/jclouds/oauth/v2/config/OAuth.java |  35 ------
 .../v2/config/OAuthAuthenticationModule.java    |  46 -------
 .../oauth/v2/config/OAuthHttpApiModule.java     |  42 -------
 .../jclouds/oauth/v2/config/OAuthModule.java    |  78 ++++--------
 .../oauth/v2/config/OAuthProperties.java        |  10 +-
 .../oauth/v2/config/PrivateKeySupplier.java     | 100 +++++++++++++++
 .../org/jclouds/oauth/v2/domain/Claims.java     |  35 ++++--
 .../org/jclouds/oauth/v2/domain/Header.java     |  41 ------
 .../jclouds/oauth/v2/domain/TokenRequest.java   |  31 -----
 .../v2/filters/BearerTokenAuthenticator.java    |  40 ------
 .../v2/filters/BearerTokenFromCredentials.java  |  44 +++++++
 .../oauth/v2/filters/JWTBearerTokenFlow.java    | 113 +++++++++++++++++
 .../v2/filters/OAuthAuthenticationFilter.java   |  27 ----
 .../oauth/v2/filters/OAuthAuthenticator.java    |  51 --------
 .../jclouds/oauth/v2/filters/OAuthFilter.java   |  23 ++++
 .../oauth/v2/functions/BuildTokenRequest.java   |  92 --------------
 .../oauth/v2/functions/ClaimsToAssertion.java   |  87 +++++++++++++
 .../jclouds/oauth/v2/functions/FetchToken.java  |  38 ------
 .../oauth/v2/functions/PrivateKeySupplier.java  | 105 ----------------
 .../v2/functions/SignOrProduceMacForToken.java  | 101 ---------------
 .../oauth/v2/handlers/OAuthErrorHandler.java    |  58 ---------
 .../oauth/v2/AuthorizationApiLiveTest.java      |  94 ++++++++++++++
 .../oauth/v2/AuthorizationApiMockTest.java      | 125 ++++++++++++++++++
 .../jclouds/oauth/v2/OAuthApiMetadataTest.java  |  39 ------
 .../oauth/v2/binders/TokenBinderTest.java       |  85 -------------
 .../oauth/v2/config/PrivateKeySupplierTest.java |  67 ++++++++++
 .../oauth/v2/features/OAuthApiLiveTest.java     |  84 -------------
 .../oauth/v2/features/OAuthApiMockTest.java     | 126 -------------------
 .../v2/functions/ClaimsToAssertionTest.java     |  48 +++++++
 .../v2/functions/PrivateKeySupplierTest.java    |  83 ------------
 .../oauth/v2/functions/SignerFunctionTest.java  |  56 ---------
 .../v2/handlers/OAuthErrorHandlerTest.java      |  92 --------------
 .../oauth/v2/internal/Base64UrlSafeTest.java    |  40 ------
 .../oauth/v2/internal/BaseOAuthApiLiveTest.java |  63 ----------
 .../BaseOAuthAuthenticatedApiLiveTest.java      | 112 -----------------
 .../jclouds/oauth/v2/parse/ParseTokenTest.java  |  40 ------
 .../oauth/src/test/resources/tokenResponse.json |   5 -
 44 files changed, 832 insertions(+), 1897 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/pom.xml
----------------------------------------------------------------------
diff --git a/apis/oauth/pom.xml b/apis/oauth/pom.xml
index 9f83ac8..f978213 100644
--- a/apis/oauth/pom.xml
+++ b/apis/oauth/pom.xml
@@ -35,7 +35,6 @@
     <test.oauth.identity>FIX_ME</test.oauth.identity>
     <test.oauth.credential>FIX_ME</test.oauth.credential>
     <test.oauth.endpoint>FIX_ME</test.oauth.endpoint>
-    <test.jclouds.oauth.jws-alg>RS256</test.jclouds.oauth.jws-alg>
     <test.jclouds.oauth.audience>FIX_ME</test.jclouds.oauth.audience>
     <test.jclouds.oauth.scope>FIX_ME</test.jclouds.oauth.scope>
     <test.oauth.api-version>2</test.oauth.api-version>

http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/AuthorizationApi.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/AuthorizationApi.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/AuthorizationApi.java
new file mode 100644
index 0000000..0a9d453
--- /dev/null
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/AuthorizationApi.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.oauth.v2;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+
+import java.io.Closeable;
+
+import javax.inject.Named;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.POST;
+
+import org.jclouds.oauth.v2.functions.ClaimsToAssertion;
+import org.jclouds.oauth.v2.config.Authorization;
+import org.jclouds.oauth.v2.domain.Claims;
+import org.jclouds.oauth.v2.domain.Token;
+import org.jclouds.rest.annotations.Endpoint;
+import org.jclouds.rest.annotations.FormParams;
+import org.jclouds.rest.annotations.ParamParser;
+
+/**
+ * Binds to an OAuth2 <a href="http://tools.ietf.org/html/rfc6749#section-3.1">authorization endpoint</a>.
+ */
+@Endpoint(Authorization.class)
+public interface AuthorizationApi extends Closeable {
+   @Named("oauth2:authorize")
+   @POST
+   @FormParams(keys = "grant_type", values = "urn:ietf:params:oauth:grant-type:jwt-bearer")
+   @Consumes(APPLICATION_JSON)
+   Token authorize(@FormParam("assertion") @ParamParser(ClaimsToAssertion.class) Claims claims);
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/JWSAlgorithms.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/JWSAlgorithms.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/JWSAlgorithms.java
deleted file mode 100644
index 072fc53..0000000
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/JWSAlgorithms.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.oauth.v2;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.security.KeyFactory;
-import java.security.NoSuchAlgorithmException;
-import java.util.List;
-
-import com.google.common.collect.ImmutableList;
-
-/**
- * JSON Web Signature Algorithms
- * <p/>
- * We only support <a href="http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-36#section-3.1">required
- * or recommended algorithms</a>, with the exception of {@code none}, which is only supported in tests.
- */
-public final class JWSAlgorithms {
-   /** This is a marker algorithm only supported in tests. */
-   public static final String NONE = "none";
-
-   private static final List<String> SUPPORTED_ALGS = ImmutableList.of("ES256", "RS256", "HS256", NONE);
-
-   /**
-    * Static mapping between the oauth algorithm name and the Crypto provider signature algorithm name and KeyFactory.
-    */
-   private static final List<List<String>> ALG_TO_SIGNATURE_ALG_AND_KEY_FACTORY = ImmutableList.<List<String>>of( //
-         ImmutableList.of(SUPPORTED_ALGS.get(0), "SHA256withECDSA", "EC"), // ECDSA using P-256 and SHA-256
-         ImmutableList.of(SUPPORTED_ALGS.get(1), "SHA256withRSA", "RSA"), // RSASSA-PKCS-v1_5 using SHA-256
-         ImmutableList.of(SUPPORTED_ALGS.get(2), "HmacSHA256", "DiffieHellman") // HMAC using SHA-256
-   );
-
-   /** Ordered list of supported algorithms by recommendation. */
-   public static List<String> supportedAlgs() {
-      return SUPPORTED_ALGS;
-   }
-
-   public static String macOrSignature(String jwsAlg) {
-      return ALG_TO_SIGNATURE_ALG_AND_KEY_FACTORY.get(indexOf(jwsAlg)).get(1);
-   }
-
-   public static KeyFactory keyFactory(String jwsAlg) {
-      String keyFactoryAlgorithm = ALG_TO_SIGNATURE_ALG_AND_KEY_FACTORY.get(indexOf(jwsAlg)).get(2);
-      try {
-         return KeyFactory.getInstance(keyFactoryAlgorithm);
-      } catch (NoSuchAlgorithmException e) {
-         throw new AssertionError("Invalid contents in JWSAlgorithms! " + e.getMessage());
-      }
-   }
-
-   private static int indexOf(String jwsAlg) {
-      int result = SUPPORTED_ALGS.indexOf(checkNotNull(jwsAlg, "jwsAlg"));
-      checkArgument(result != -1, "JSON Web Signature alg %s is not in the supported list %s", jwsAlg, SUPPORTED_ALGS);
-      return result;
-   }
-
-   private JWSAlgorithms() {
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApi.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApi.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApi.java
deleted file mode 100644
index 770e5e8..0000000
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApi.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.oauth.v2;
-
-import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
-
-import java.io.Closeable;
-
-import javax.inject.Named;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.POST;
-
-import org.jclouds.oauth.v2.binders.TokenBinder;
-import org.jclouds.oauth.v2.config.OAuth;
-import org.jclouds.oauth.v2.domain.Token;
-import org.jclouds.oauth.v2.domain.TokenRequest;
-import org.jclouds.rest.AuthorizationException;
-import org.jclouds.rest.annotations.BinderParam;
-import org.jclouds.rest.annotations.Endpoint;
-
-/**
- * Provides access to OAuth via REST api.
- * <p/>
- * Usually this is not directly used by a client, which instead specifies
- * OAuthAuthenticator as a request filter, which in turn uses this class to
- * perform token requests.
- */
-@Endpoint(OAuth.class)
-public interface OAuthApi extends Closeable {
-
-   /**
-    * Authenticates/Authorizes access to a resource defined in TokenRequest
-    * against an OAuth v2 authentication/authorization server.
-    * 
-    * @param tokenRequest
-    *           specified the principal and the required permissions
-    * @return a Token object with the token required to access the resource
-    *         along with its expiration time
-    * @throws AuthorizationException
-    *            if the principal cannot be authenticated or has no permissions
-    *            for the specifed resources.
-    */
-   @Named("authenticate")
-   @POST
-   @Consumes(APPLICATION_JSON)
-   Token authenticate(@BinderParam(TokenBinder.class) TokenRequest tokenRequest) throws AuthorizationException;
-}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApiMetadata.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApiMetadata.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApiMetadata.java
deleted file mode 100644
index 66f61bb..0000000
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/OAuthApiMetadata.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.oauth.v2;
-
-import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
-import static org.jclouds.oauth.v2.config.CredentialType.P12_PRIVATE_KEY_CREDENTIALS;
-import static org.jclouds.oauth.v2.config.OAuthProperties.CREDENTIAL_TYPE;
-import static org.jclouds.oauth.v2.config.OAuthProperties.JWS_ALG;
-
-import java.net.URI;
-import java.util.Properties;
-
-import org.jclouds.apis.ApiMetadata;
-import org.jclouds.oauth.v2.config.OAuthHttpApiModule;
-import org.jclouds.oauth.v2.config.OAuthModule;
-import org.jclouds.rest.internal.BaseHttpApiMetadata;
-
-import com.google.auto.service.AutoService;
-import com.google.common.collect.ImmutableSet;
-import com.google.inject.Module;
-
-@AutoService(ApiMetadata.class)
-public class OAuthApiMetadata extends BaseHttpApiMetadata<OAuthApi> {
-
-   @Override
-   public Builder toBuilder() {
-      return new Builder().fromApiMetadata(this);
-   }
-
-   public OAuthApiMetadata() {
-      this(new Builder());
-   }
-
-   protected OAuthApiMetadata(Builder builder) {
-      super(builder);
-   }
-
-   public static Properties defaultProperties() {
-      Properties properties = BaseHttpApiMetadata.defaultProperties();
-      properties.put(JWS_ALG, "RS256");
-      properties.put(CREDENTIAL_TYPE, P12_PRIVATE_KEY_CREDENTIALS);
-      properties.put(PROPERTY_SESSION_INTERVAL, 3600);
-      return properties;
-   }
-
-   public static class Builder extends BaseHttpApiMetadata.Builder<OAuthApi, Builder> {
-
-      protected Builder() {
-         id("oauth")
-         .name("OAuth API")
-         .identityName("service_account")
-         .credentialName("service_key")
-         .documentation(URI.create("TODO"))
-         .version("2")
-         .defaultProperties(OAuthApiMetadata.defaultProperties())
-         .defaultModules(ImmutableSet.<Class<? extends Module>>of(OAuthModule.class, OAuthHttpApiModule.class));
-      }
-
-      @Override
-      public OAuthApiMetadata build() {
-         return new OAuthApiMetadata(this);
-      }
-
-      @Override
-      protected Builder self() {
-         return this;
-      }
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/binders/TokenBinder.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/binders/TokenBinder.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/binders/TokenBinder.java
deleted file mode 100644
index 0782000..0000000
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/binders/TokenBinder.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.oauth.v2.binders;
-
-import static com.google.common.base.Charsets.UTF_8;
-import static com.google.common.base.Joiner.on;
-import static com.google.common.io.BaseEncoding.base64Url;
-import static org.jclouds.io.Payloads.newUrlEncodedFormPayload;
-
-import javax.inject.Inject;
-
-import org.jclouds.http.HttpRequest;
-import org.jclouds.io.Payload;
-import org.jclouds.json.Json;
-import org.jclouds.oauth.v2.domain.TokenRequest;
-import org.jclouds.rest.Binder;
-
-import com.google.common.base.Function;
-import com.google.common.base.Supplier;
-import com.google.common.collect.ImmutableMultimap;
-
-/**
- * Formats a token request into JWT format namely:
- * <ol>
- * <li>Transforms the token request to json.</li>
- * <li>Creates the base64 header.claimset portions of the payload.</li>
- * <li>Uses the provided signer function to create a signature.</li>
- * <li>Creates the full url encoded payload as described in: <a href="https://developers.google.com/accounts/docs/OAuth2ServiceAccount">OAuth2ServiceAccount</a></li>
- * </ol>
- */
-public final class TokenBinder implements Binder {
-   private static final String ASSERTION_FORM_PARAM = "assertion";
-   private static final String GRANT_TYPE_FORM_PARAM = "grant_type";
-   private static final String GRANT_TYPE_JWT_BEARER = "urn:ietf:params:oauth:grant-type:jwt-bearer";
-
-   private final Supplier<Function<byte[], byte[]>> signer;
-   private final Json json;
-
-   @Inject TokenBinder(Supplier<Function<byte[], byte[]>> signer, Json json) {
-      this.signer = signer;
-      this.json = json;
-   }
-
-   @Override public <R extends HttpRequest> R bindToRequest(R request, Object input) {
-      TokenRequest tokenRequest = (TokenRequest) input;
-      String encodedHeader = json.toJson(tokenRequest.header());
-      String encodedClaimSet = json.toJson(tokenRequest.claimSet());
-
-      encodedHeader = base64Url().omitPadding().encode(encodedHeader.getBytes(UTF_8));
-      encodedClaimSet = base64Url().omitPadding().encode(encodedClaimSet.getBytes(UTF_8));
-
-      byte[] signature = signer.get().apply(on(".").join(encodedHeader, encodedClaimSet).getBytes(UTF_8));
-      String encodedSignature = signature != null ?  base64Url().omitPadding().encode(signature) : "";
-
-      // the final assertion in base 64 encoded {header}.{claimSet}.{signature} format
-      String assertion = on(".").join(encodedHeader, encodedClaimSet, encodedSignature);
-      Payload payload = newUrlEncodedFormPayload(ImmutableMultimap.<String, String> builder()
-            .put(GRANT_TYPE_FORM_PARAM, GRANT_TYPE_JWT_BEARER)
-            .put(ASSERTION_FORM_PARAM, assertion).build());
-
-      return (R) request.toBuilder().payload(payload).build();
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/Authorization.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/Authorization.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/Authorization.java
new file mode 100644
index 0000000..cefc5ac
--- /dev/null
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/Authorization.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.oauth.v2.config;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import javax.inject.Qualifier;
+
+@Retention(value = RetentionPolicy.RUNTIME)
+@Target(value = {ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
+@Qualifier
+public @interface Authorization {
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuth.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuth.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuth.java
deleted file mode 100644
index 6255e50..0000000
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuth.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.oauth.v2.config;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-import javax.inject.Qualifier;
-
-/**
- * Qualifies OAuth related resources, such as Endpoint.
- *
- * @see org.jclouds.oauth.v2.OAuthApi
- */
-@Retention(value = RetentionPolicy.RUNTIME)
-@Target(value = {ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
-@Qualifier
-public @interface OAuth {
-}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthAuthenticationModule.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthAuthenticationModule.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthAuthenticationModule.java
deleted file mode 100644
index 4d238f1..0000000
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthAuthenticationModule.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.oauth.v2.config;
-
-import static org.jclouds.rest.config.BinderUtils.bindHttpApi;
-
-import java.net.URI;
-
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-import org.jclouds.oauth.v2.OAuthApi;
-
-import com.google.common.base.Supplier;
-import com.google.common.base.Suppliers;
-import com.google.inject.AbstractModule;
-import com.google.inject.Provides;
-
-public class OAuthAuthenticationModule extends AbstractModule {
-
-   @Override
-   protected void configure() {
-      bindHttpApi(binder(), OAuthApi.class);
-   }
-
-   @Provides
-   @Singleton
-   @OAuth
-   protected Supplier<URI> oauthEndpoint(@Named("oauth.endpoint") String endpoint) {
-      return Suppliers.ofInstance(URI.create(endpoint));
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthHttpApiModule.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthHttpApiModule.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthHttpApiModule.java
deleted file mode 100644
index 5a1d5d2..0000000
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthHttpApiModule.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.oauth.v2.config;
-
-import java.net.URI;
-
-import javax.inject.Singleton;
-
-import org.jclouds.oauth.v2.OAuthApi;
-import org.jclouds.providers.ProviderMetadata;
-import org.jclouds.rest.ConfiguresHttpApi;
-import org.jclouds.rest.config.HttpApiModule;
-
-import com.google.common.base.Supplier;
-import com.google.common.base.Suppliers;
-import com.google.inject.Provides;
-
-/** Api module to when accessing OAuth stand-alone. */
-@ConfiguresHttpApi
-public class OAuthHttpApiModule extends HttpApiModule<OAuthApi> {
-
-   @Provides
-   @Singleton
-   @OAuth
-   protected Supplier<URI> provideAuthenticationEndpoint(ProviderMetadata providerMetadata) {
-      return Suppliers.ofInstance(URI.create(providerMetadata.getEndpoint()));
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthModule.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthModule.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthModule.java
index e6d5985..8a3568c 100644
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthModule.java
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthModule.java
@@ -16,82 +16,48 @@
  */
 package org.jclouds.oauth.v2.config;
 
-import static java.util.concurrent.TimeUnit.SECONDS;
-import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
-import static org.jclouds.oauth.v2.JWSAlgorithms.NONE;
-import static org.jclouds.oauth.v2.config.OAuthProperties.JWS_ALG;
+import static org.jclouds.oauth.v2.config.CredentialType.P12_PRIVATE_KEY_CREDENTIALS;
+import static org.jclouds.oauth.v2.config.OAuthProperties.CREDENTIAL_TYPE;
+import static org.jclouds.rest.config.BinderUtils.bindHttpApi;
 
+import java.net.URI;
 import java.security.PrivateKey;
 
-import org.jclouds.http.HttpRequest;
-import org.jclouds.oauth.v2.domain.Token;
-import org.jclouds.oauth.v2.domain.TokenRequest;
-import org.jclouds.oauth.v2.filters.BearerTokenAuthenticator;
-import org.jclouds.oauth.v2.filters.OAuthAuthenticationFilter;
-import org.jclouds.oauth.v2.filters.OAuthAuthenticator;
-import org.jclouds.oauth.v2.functions.BuildTokenRequest;
-import org.jclouds.oauth.v2.functions.FetchToken;
-import org.jclouds.oauth.v2.functions.PrivateKeySupplier;
-import org.jclouds.oauth.v2.functions.SignOrProduceMacForToken;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.oauth.v2.AuthorizationApi;
+import org.jclouds.oauth.v2.filters.BearerTokenFromCredentials;
+import org.jclouds.oauth.v2.filters.JWTBearerTokenFlow;
+import org.jclouds.oauth.v2.filters.OAuthFilter;
 
-import com.google.common.base.Function;
-import com.google.common.base.Functions;
 import com.google.common.base.Supplier;
 import com.google.common.base.Suppliers;
-import com.google.common.cache.CacheBuilder;
-import com.google.common.cache.CacheLoader;
-import com.google.common.cache.LoadingCache;
 import com.google.inject.AbstractModule;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Provides;
-import com.google.inject.Singleton;
 import com.google.inject.TypeLiteral;
-import com.google.inject.name.Named;
 
-public class OAuthModule extends AbstractModule {
+public final class OAuthModule extends AbstractModule {
 
    @Override protected void configure() {
+      bindHttpApi(binder(), AuthorizationApi.class);
       bind(CredentialType.class).toProvider(CredentialTypeFromPropertyOrDefault.class);
-      bind(new TypeLiteral<Function<HttpRequest, TokenRequest>>() {}).to(BuildTokenRequest.class);
-      bind(new TypeLiteral<Function<TokenRequest, Token>>() {}).to(FetchToken.class);
-      bind(new TypeLiteral<Supplier<PrivateKey>>() {}).annotatedWith(OAuth.class).to(PrivateKeySupplier.class);
+      bind(new TypeLiteral<Supplier<PrivateKey>>() {}).annotatedWith(Authorization.class).to(PrivateKeySupplier.class);
    }
 
-   /**
-    * Provides a cache for tokens. Cache is time based and by default expires after 59 minutes 
-    * (the maximum time a token is valid is 60 minutes).
-    * This cache and expiry period is system-wide and does not attend to per-instance expiry time
-    * (e.g. "expires_in" from Google Compute -- which is set to the standard 3600 seconds).
-    */
-   // NB: If per-instance expiry time is required, significant refactoring will be needed.
    @Provides
-   @Singleton
-   public LoadingCache<TokenRequest, Token> provideAccessCache(Function<TokenRequest, Token> getAccess,
-                                                               @Named(PROPERTY_SESSION_INTERVAL) long expirationSeconds) {
-      // since the session interval is also the token expiration time requested to the server make the token expire a
-      // bit before the deadline to make sure there aren't session expiration exceptions
-      expirationSeconds = expirationSeconds > 30 ? expirationSeconds - 30 : expirationSeconds;
-      return CacheBuilder.newBuilder().expireAfterWrite(expirationSeconds, SECONDS).build(CacheLoader.from(getAccess));
-   }
-
-   /**
-    * Defers instantiation of {@linkplain SignOrProduceMacForToken} so as to avoid requiring private keys when the alg
-    * is set to {@linkplain org.jclouds.oauth.v2.JWSAlgorithms#NONE}.
-    */
-   @Provides @Singleton Supplier<Function<byte[], byte[]>> signOrProduceMacForToken(@Named(JWS_ALG) String jwsAlg,
-         Provider<SignOrProduceMacForToken> in) {
-      if (jwsAlg.equals(NONE)) { // Current implementation requires we return null on none.
-         return (Supplier) Suppliers.ofInstance(Functions.constant(null));
-      }
-      return Suppliers.memoize(in.get());
+   @Authorization
+   protected Supplier<URI> oauthEndpoint(@javax.inject.Named("oauth.endpoint") String endpoint) {
+      return Suppliers.ofInstance(URI.create(endpoint));
    }
 
    @Singleton
    public static class CredentialTypeFromPropertyOrDefault implements Provider<CredentialType> {
       @Inject(optional = true)
-      @Named(OAuthProperties.CREDENTIAL_TYPE)
-      String credentialType = CredentialType.P12_PRIVATE_KEY_CREDENTIALS.toString();
+      @Named(CREDENTIAL_TYPE)
+      String credentialType = P12_PRIVATE_KEY_CREDENTIALS.toString();
 
       @Override
       public CredentialType get() {
@@ -101,9 +67,9 @@ public class OAuthModule extends AbstractModule {
 
    @Provides
    @Singleton
-   protected OAuthAuthenticationFilter authenticationFilterForCredentialType(CredentialType credentialType,
-                                                                             OAuthAuthenticator serviceAccountAuth,
-                                                                             BearerTokenAuthenticator bearerTokenAuth) {
+   protected OAuthFilter authenticationFilterForCredentialType(CredentialType credentialType,
+                                                               JWTBearerTokenFlow serviceAccountAuth,
+                                                               BearerTokenFromCredentials bearerTokenAuth) {
       switch (credentialType) {
          case P12_PRIVATE_KEY_CREDENTIALS:
             return serviceAccountAuth;

http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthProperties.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthProperties.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthProperties.java
index 197bc31..7faed0c 100644
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthProperties.java
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/OAuthProperties.java
@@ -16,18 +16,16 @@
  */
 package org.jclouds.oauth.v2.config;
 
-import org.jclouds.oauth.v2.JWSAlgorithms;
+public final class OAuthProperties {
 
-public class OAuthProperties {
-
-   /** The JSON Web Signature alg, from the {@link JWSAlgorithms#supportedAlgs() supported list}. */
+   /** The JSON Web Signature alg, must be {@code RS256} or {@code none}. */
    public static final String JWS_ALG = "jclouds.oauth.jws-alg";
 
    /**
     * The oauth audience, who this token is intended for. For instance in JWT and for
     * google API's this property maps to: {"aud","https://accounts.google.com/o/oauth2/token"}
     *
-    * @see <a href="http://tools.ietf.org/html/draft-jones-json-web-token-04">doc</a>
+    * @see <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-30">doc</a>
     */
    public static final String AUDIENCE = "jclouds.oauth.audience";
 
@@ -38,4 +36,6 @@ public class OAuthProperties {
     */
    public static final String CREDENTIAL_TYPE = "jclouds.oauth.credential-type";
 
+   private OAuthProperties() {
+   }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/PrivateKeySupplier.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/PrivateKeySupplier.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/PrivateKeySupplier.java
new file mode 100644
index 0000000..4873dc9
--- /dev/null
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/config/PrivateKeySupplier.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.oauth.v2.config;
+
+import static com.google.common.base.Charsets.UTF_8;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Throwables.propagate;
+import static org.jclouds.crypto.Pems.privateKeySpec;
+import static org.jclouds.util.Throwables2.getFirstThrowableOfType;
+
+import java.io.IOException;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.spec.InvalidKeySpecException;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.domain.Credentials;
+import org.jclouds.location.Provider;
+import org.jclouds.rest.AuthorizationException;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Supplier;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.io.ByteSource;
+import com.google.common.util.concurrent.UncheckedExecutionException;
+
+/**
+ * Loads {@link PrivateKey} from a pem private key using and RSA KeyFactory. The pem pk algorithm must match the
+ * KeyFactory algorithm.
+ */
+@Singleton // due to cache
+final class PrivateKeySupplier implements Supplier<PrivateKey> {
+
+   private final Supplier<Credentials> creds;
+   private final LoadingCache<Credentials, PrivateKey> keyCache;
+
+   @Inject PrivateKeySupplier(@Provider Supplier<Credentials> creds, PrivateKeyForCredentials loader) {
+      this.creds = creds;
+      // throw out the private key related to old credentials
+      this.keyCache = CacheBuilder.newBuilder().maximumSize(2).build(checkNotNull(loader, "loader"));
+   }
+
+   /**
+    * it is relatively expensive to extract a private key from a PEM. cache the relationship between current
+    * credentials
+    * so that the private key is only recalculated once.
+    */
+   @VisibleForTesting
+   static final class PrivateKeyForCredentials extends CacheLoader<Credentials, PrivateKey> {
+
+      @Override public PrivateKey load(Credentials in) {
+         try {
+            String privateKeyInPemFormat = checkNotNull(in.credential, "credential in PEM format");
+            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+            return keyFactory.generatePrivate(privateKeySpec(ByteSource.wrap(privateKeyInPemFormat.getBytes(UTF_8))));
+         } catch (NoSuchAlgorithmException e) {
+            throw new AssertionError(e);
+         } catch (IOException e) {
+            throw propagate(e);
+         } catch (InvalidKeySpecException e) {
+            throw new AuthorizationException("security exception loading credentials. " + e.getMessage(), e);
+            // catch IAE that is thrown when parsing the pk fails
+         } catch (IllegalArgumentException e) {
+            throw new AuthorizationException("cannot parse pk. " + e.getMessage(), e);
+         }
+      }
+   }
+
+   @Override public PrivateKey get() {
+      try {
+         // loader always throws UncheckedExecutionException so no point in using get()
+         return keyCache.getUnchecked(checkNotNull(creds.get(), "credential supplier returned null"));
+      } catch (UncheckedExecutionException e) {
+         AuthorizationException authorizationException = getFirstThrowableOfType(e, AuthorizationException.class);
+         if (authorizationException != null) {
+            throw authorizationException;
+         }
+         throw e;
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Claims.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Claims.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Claims.java
index 07b03f6..9087acd 100644
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Claims.java
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Claims.java
@@ -16,19 +16,40 @@
  */
 package org.jclouds.oauth.v2.domain;
 
+import org.jclouds.json.SerializedNames;
+
+import com.google.auto.value.AutoValue;
+
 /**
- * Description of Claims corresponding to a {@linkplain Token JWT Token}.
+ * Claims corresponding to a {@linkplain Token JWT Token}.
  *
  * @see <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-30#section-4">registered list</a>
  */
-public final class Claims {
+@AutoValue
+public abstract class Claims {
+   /** The issuer of this token. In google, the service account email. */
+   public abstract String iss();
+
+   /** A comma-separated list of scopes needed to perform the request. */
+   public abstract String scope();
+
+   /**
+    * The oauth audience, who this token is intended for. For instance in JWT and for
+    * google API's, this maps to: {@code https://accounts.google.com/o/oauth2/token}
+    */
+   public abstract String aud();
+
+   /** The expiration time, in seconds since {@link #iat()}. */
+   public abstract long exp();
+
    /** The time at which the JWT was issued, in seconds since the epoch. */
-   public static final String ISSUED_AT = "iat";
+   public abstract long iat();
 
-   /** The expiration time, in seconds since {@link #ISSUED_AT}. */
-   public static final String EXPIRATION_TIME = "exp";
+   @SerializedNames({ "iss", "scope", "aud", "exp", "iat" })
+   public static Claims create(String iss, String scope, String aud, long exp, long iat) {
+      return new AutoValue_Claims(iss, scope, aud, exp, iat);
+   }
 
-   private Claims(){
-      throw new AssertionError("intentionally unimplemented");
+   Claims() {
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Header.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Header.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Header.java
deleted file mode 100644
index 9cdd924..0000000
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/Header.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.oauth.v2.domain;
-
-import org.jclouds.json.SerializedNames;
-
-import com.google.auto.value.AutoValue;
-
-/**
- * The header for the OAuth token, contains the signer algorithm's name and the type of the token
- *
- * @see <a href="https://developers.google.com/accounts/docs/OAuth2ServiceAccount">doc</a>
- */
-@AutoValue
-public abstract class Header {
-
-   /** The name of the algorithm used to compute the signature, e.g., {@code ES256}. */
-   public abstract String signerAlgorithm();
-
-   /** The type of the token, e.g., {@code JWT}. */
-   public abstract String type();
-
-   @SerializedNames({ "alg", "typ" })
-   public static Header create(String signerAlgorithm, String type){
-      return new AutoValue_Header(signerAlgorithm, type);
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/TokenRequest.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/TokenRequest.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/TokenRequest.java
deleted file mode 100644
index b08a20b..0000000
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/domain/TokenRequest.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.oauth.v2.domain;
-
-import java.util.Map;
-
-import com.google.auto.value.AutoValue;
-
-@AutoValue
-public abstract class TokenRequest {
-   public abstract Header header();
-   public abstract Map<String, Object> claimSet();
-
-   public static TokenRequest create(Header header, Map<String, Object> claims) {
-      return new AutoValue_TokenRequest(header, claims);
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/BearerTokenAuthenticator.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/BearerTokenAuthenticator.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/BearerTokenAuthenticator.java
deleted file mode 100644
index 3d7d92d..0000000
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/BearerTokenAuthenticator.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.oauth.v2.filters;
-
-import static java.lang.String.format;
-
-import javax.inject.Inject;
-
-import org.jclouds.domain.Credentials;
-import org.jclouds.http.HttpException;
-import org.jclouds.http.HttpRequest;
-import org.jclouds.location.Provider;
-
-import com.google.common.base.Supplier;
-
-public final class BearerTokenAuthenticator implements OAuthAuthenticationFilter {
-   private final Supplier<Credentials> creds;
-
-   @Inject BearerTokenAuthenticator(@Provider Supplier<Credentials> creds) {
-      this.creds = creds;
-   }
-
-   @Override public HttpRequest filter(HttpRequest request) throws HttpException {
-      return request.toBuilder().addHeader("Authorization", format("%s %s", "Bearer", creds.get().credential)).build();
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/BearerTokenFromCredentials.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/BearerTokenFromCredentials.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/BearerTokenFromCredentials.java
new file mode 100644
index 0000000..61eacf1
--- /dev/null
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/BearerTokenFromCredentials.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.oauth.v2.filters;
+
+import static java.lang.String.format;
+
+import javax.inject.Inject;
+
+import org.jclouds.domain.Credentials;
+import org.jclouds.http.HttpException;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.location.Provider;
+
+import com.google.common.base.Supplier;
+
+/**
+ * When the user supplies {@link org.jclouds.oauth.v2.config.CredentialType#BEARER_TOKEN_CREDENTIALS}, the credential
+ * is a literal bearer token. This filter applies that to the request.
+ */
+public final class BearerTokenFromCredentials implements OAuthFilter {
+   private final Supplier<Credentials> creds;
+
+   @Inject BearerTokenFromCredentials(@Provider Supplier<Credentials> creds) {
+      this.creds = creds;
+   }
+
+   @Override public HttpRequest filter(HttpRequest request) throws HttpException {
+      return request.toBuilder().addHeader("Authorization", format("%s %s", "Bearer", creds.get().credential)).build();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/JWTBearerTokenFlow.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/JWTBearerTokenFlow.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/JWTBearerTokenFlow.java
new file mode 100644
index 0000000..466c8e3
--- /dev/null
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/JWTBearerTokenFlow.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.oauth.v2.filters;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
+import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.jclouds.domain.Credentials;
+import org.jclouds.http.HttpException;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.location.Provider;
+import org.jclouds.oauth.v2.AuthorizationApi;
+import org.jclouds.oauth.v2.config.OAuthScopes;
+import org.jclouds.oauth.v2.domain.Claims;
+import org.jclouds.oauth.v2.domain.Token;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Supplier;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+
+/**
+ * Authorizes new Bearer Tokens at runtime by authorizing claims needed for the http request.
+ *
+ * <h3>Cache</h3>
+ * This maintains a time-based Bearer Token cache. By default expires after 59 minutes
+ * (the maximum time a token is valid is 60 minutes).
+ * This cache and expiry period is system-wide and does not attend to per-instance expiry time
+ * (e.g. "expires_in" from Google Compute -- which is set to the standard 3600 seconds).
+ */
+public class JWTBearerTokenFlow implements OAuthFilter {
+   private static final Joiner ON_COMMA = Joiner.on(",");
+
+   private final String audience;
+   private final Supplier<Credentials> credentialsSupplier;
+   private final OAuthScopes scopes;
+   private final long tokenDuration;
+   private final LoadingCache<Claims, Token> tokenCache;
+
+   public static class TestJWTBearerTokenFlow extends JWTBearerTokenFlow {
+
+      @Inject TestJWTBearerTokenFlow(AuthorizeToken loader, @Named(PROPERTY_SESSION_INTERVAL) long tokenDuration,
+            @Named(AUDIENCE) String audience, @Provider Supplier<Credentials> credentialsSupplier, OAuthScopes scopes) {
+         super(loader, tokenDuration, audience, credentialsSupplier, scopes);
+      }
+
+      /** Constant time for testing. */
+      long currentTimeSeconds() {
+         return 0;
+      }
+   }
+
+   @Inject JWTBearerTokenFlow(AuthorizeToken loader, @Named(PROPERTY_SESSION_INTERVAL) long tokenDuration,
+         @Named(AUDIENCE) String audience, @Provider Supplier<Credentials> credentialsSupplier, OAuthScopes scopes) {
+      this.audience = audience;
+      this.credentialsSupplier = credentialsSupplier;
+      this.scopes = scopes;
+      this.tokenDuration = tokenDuration;
+      // since the session interval is also the token expiration time requested to the server make the token expire a
+      // bit before the deadline to make sure there aren't session expiration exceptions
+      long cacheExpirationSeconds = tokenDuration > 30 ? tokenDuration - 30 : tokenDuration;
+      this.tokenCache = CacheBuilder.newBuilder().expireAfterWrite(tokenDuration, SECONDS).build(loader);
+   }
+
+   static final class AuthorizeToken extends CacheLoader<Claims, Token> {
+      private final AuthorizationApi api;
+
+      @Inject AuthorizeToken(AuthorizationApi api) {
+         this.api = api;
+      }
+
+      @Override public Token load(Claims key) throws Exception {
+         return api.authorize(key);
+      }
+   }
+
+   @Override public HttpRequest filter(HttpRequest request) throws HttpException {
+      long now = currentTimeSeconds();
+      Claims claims = Claims.create( //
+            credentialsSupplier.get().identity, // iss
+            ON_COMMA.join(scopes.forRequest(request)), // scope
+            audience, // aud
+            now + tokenDuration, // exp
+            now // iat
+      );
+      Token token = tokenCache.getUnchecked(claims);
+      String authorization = String.format("%s %s", token.tokenType(), token.accessToken());
+      return request.toBuilder().addHeader("Authorization", authorization).build();
+   }
+
+   long currentTimeSeconds() {
+      return System.currentTimeMillis() / 1000;
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticationFilter.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticationFilter.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticationFilter.java
deleted file mode 100644
index e6e5714..0000000
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticationFilter.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.oauth.v2.filters;
-
-import org.jclouds.http.HttpRequestFilter;
-
-/**
- * Marker interface to specify auth mechanism (credentials or bearer token)
- *
- */
-public interface OAuthAuthenticationFilter extends HttpRequestFilter {
-
-}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticator.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticator.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticator.java
deleted file mode 100644
index cb858b5..0000000
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthAuthenticator.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.oauth.v2.filters;
-
-import javax.inject.Inject;
-
-import org.jclouds.http.HttpException;
-import org.jclouds.http.HttpRequest;
-import org.jclouds.oauth.v2.domain.Token;
-import org.jclouds.oauth.v2.domain.TokenRequest;
-
-import com.google.common.base.Function;
-import com.google.common.cache.LoadingCache;
-
-/**
- * To be used by client applications to embed an OAuth authentication in their REST requests.
- * <p/>
- * TODO when we're able to use the OAuthAuthentication an this should be used automatically
- */
-public final class OAuthAuthenticator implements OAuthAuthenticationFilter {
-
-   private Function<HttpRequest, TokenRequest> tokenRequestBuilder;
-   private Function<TokenRequest, Token> tokenFetcher;
-
-   @Inject OAuthAuthenticator(Function<HttpRequest, TokenRequest> tokenRequestBuilder,
-         LoadingCache<TokenRequest, Token> tokenFetcher) {
-      this.tokenRequestBuilder = tokenRequestBuilder;
-      this.tokenFetcher = tokenFetcher;
-   }
-
-   @Override public HttpRequest filter(HttpRequest request) throws HttpException {
-      TokenRequest tokenRequest = tokenRequestBuilder.apply(request);
-      Token token = tokenFetcher.apply(tokenRequest);
-      String authorization = String.format("%s %s", token.tokenType(), token.accessToken());
-      return request.toBuilder().addHeader("Authorization", authorization).build();
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthFilter.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthFilter.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthFilter.java
new file mode 100644
index 0000000..fa07d1e
--- /dev/null
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/filters/OAuthFilter.java
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.oauth.v2.filters;
+
+import org.jclouds.http.HttpRequestFilter;
+
+/** Indicates use of auth mechanism according to {@link org.jclouds.oauth.v2.config.OAuthProperties#CREDENTIAL_TYPE). */
+public interface OAuthFilter extends HttpRequestFilter {
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/BuildTokenRequest.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/BuildTokenRequest.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/BuildTokenRequest.java
deleted file mode 100644
index 51ab318..0000000
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/BuildTokenRequest.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.oauth.v2.functions;
-
-import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
-import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE;
-import static org.jclouds.oauth.v2.config.OAuthProperties.JWS_ALG;
-import static org.jclouds.oauth.v2.domain.Claims.EXPIRATION_TIME;
-import static org.jclouds.oauth.v2.domain.Claims.ISSUED_AT;
-
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import javax.inject.Inject;
-import javax.inject.Named;
-
-import org.jclouds.domain.Credentials;
-import org.jclouds.http.HttpRequest;
-import org.jclouds.location.Provider;
-import org.jclouds.oauth.v2.config.OAuthScopes;
-import org.jclouds.oauth.v2.domain.Header;
-import org.jclouds.oauth.v2.domain.TokenRequest;
-
-import com.google.common.base.Function;
-import com.google.common.base.Joiner;
-import com.google.common.base.Supplier;
-
-/** Builds the default token request with the following claims: {@code iss,scope,aud,iat,exp}. */
-public class BuildTokenRequest implements Function<HttpRequest, TokenRequest> {
-   private static final Joiner ON_COMMA = Joiner.on(",");
-
-   private final String assertionTargetDescription;
-   private final String signatureAlgorithm;
-   private final Supplier<Credentials> credentialsSupplier;
-   private final OAuthScopes scopes;
-   private final long tokenDuration;
-
-   public static class TestBuildTokenRequest extends BuildTokenRequest {
-      @Inject TestBuildTokenRequest(@Named(AUDIENCE) String assertionTargetDescription,
-            @Named(JWS_ALG) String signatureAlgorithm, @Provider Supplier<Credentials> credentialsSupplier,
-            OAuthScopes scopes, @Named(PROPERTY_SESSION_INTERVAL) long tokenDuration) {
-         super(assertionTargetDescription, signatureAlgorithm, credentialsSupplier, scopes, tokenDuration);
-      }
-
-      public long currentTimeSeconds() {
-         return 0;
-      }
-   }
-
-   @Inject BuildTokenRequest(@Named(AUDIENCE) String assertionTargetDescription,
-         @Named(JWS_ALG) String signatureAlgorithm, @Provider Supplier<Credentials> credentialsSupplier,
-         OAuthScopes scopes, @Named(PROPERTY_SESSION_INTERVAL) long tokenDuration) {
-      this.assertionTargetDescription = assertionTargetDescription;
-      this.signatureAlgorithm = signatureAlgorithm;
-      this.credentialsSupplier = credentialsSupplier;
-      this.scopes = scopes;
-      this.tokenDuration = tokenDuration;
-   }
-
-   @Override public TokenRequest apply(HttpRequest request) {
-      Header header = Header.create(signatureAlgorithm, "JWT");
-
-      Map<String, Object> claims = new LinkedHashMap<String, Object>();
-      claims.put("iss", credentialsSupplier.get().identity);
-      claims.put("scope", ON_COMMA.join(scopes.forRequest(request)));
-      claims.put("aud", assertionTargetDescription);
-
-      long now = currentTimeSeconds();
-      claims.put(EXPIRATION_TIME, now + tokenDuration);
-      claims.put(ISSUED_AT, now);
-
-      return TokenRequest.create(header, claims);
-   }
-
-   long currentTimeSeconds() {
-      return System.currentTimeMillis() / 1000;
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/ClaimsToAssertion.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/ClaimsToAssertion.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/ClaimsToAssertion.java
new file mode 100644
index 0000000..d40f12e
--- /dev/null
+++ b/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/ClaimsToAssertion.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.oauth.v2.functions;
+
+import static com.google.common.base.Charsets.UTF_8;
+import static com.google.common.base.Joiner.on;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.io.BaseEncoding.base64Url;
+import static org.jclouds.oauth.v2.config.OAuthProperties.JWS_ALG;
+
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.util.List;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.jclouds.json.Json;
+import org.jclouds.oauth.v2.config.Authorization;
+import org.jclouds.rest.AuthorizationException;
+
+import com.google.common.base.Function;
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableList;
+
+public final class ClaimsToAssertion implements Function<Object, String> {
+   private static final List<String> SUPPORTED_ALGS = ImmutableList.of("RS256", "none");
+
+   private final Supplier<PrivateKey> privateKey;
+   private final Json json;
+   private final String alg;
+
+   @Inject ClaimsToAssertion(@Named(JWS_ALG) String alg, @Authorization Supplier<PrivateKey> privateKey, Json json) {
+      this.alg = alg;
+      checkArgument(SUPPORTED_ALGS.contains(alg), "%s %s not in supported list", JWS_ALG, alg, SUPPORTED_ALGS);
+      this.privateKey = privateKey;
+      this.json = json;
+   }
+
+   @Override public String apply(Object input) {
+      String encodedHeader = String.format("{\"alg\":\"%s\",\"typ\":\"JWT\"}", alg);
+      String encodedClaimSet = json.toJson(input);
+
+      encodedHeader = base64Url().omitPadding().encode(encodedHeader.getBytes(UTF_8));
+      encodedClaimSet = base64Url().omitPadding().encode(encodedClaimSet.getBytes(UTF_8));
+
+      byte[] signature = alg.equals("none")
+            ? null
+            : sha256(privateKey.get(), on(".").join(encodedHeader, encodedClaimSet).getBytes(UTF_8));
+      String encodedSignature = signature != null ?  base64Url().omitPadding().encode(signature) : "";
+
+      // the final assertion in base 64 encoded {header}.{claimSet}.{signature} format
+      return on(".").join(encodedHeader, encodedClaimSet, encodedSignature);
+   }
+
+   static byte[] sha256(PrivateKey privateKey, byte[] input) {
+      try {
+         Signature signature = Signature.getInstance("SHA256withRSA");
+         signature.initSign(privateKey);
+         signature.update(input);
+         return signature.sign();
+      } catch (NoSuchAlgorithmException e) {
+         throw new AssertionError(e);
+      } catch (SignatureException e) {
+         throw new AuthorizationException(e);
+      } catch (InvalidKeyException e) {
+         throw new AuthorizationException(e);
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/FetchToken.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/FetchToken.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/FetchToken.java
deleted file mode 100644
index 1a02cab..0000000
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/FetchToken.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.oauth.v2.functions;
-
-import javax.inject.Inject;
-
-import org.jclouds.oauth.v2.OAuthApi;
-import org.jclouds.oauth.v2.domain.Token;
-import org.jclouds.oauth.v2.domain.TokenRequest;
-
-import com.google.common.base.Function;
-
-public final class FetchToken implements Function<TokenRequest, Token> {
-
-   private final OAuthApi oAuthApi;
-
-   @Inject FetchToken(OAuthApi oAuthApi) {
-      this.oAuthApi = oAuthApi;
-   }
-
-   @Override public Token apply(TokenRequest input) {
-      return this.oAuthApi.authenticate(input);
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/PrivateKeySupplier.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/PrivateKeySupplier.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/PrivateKeySupplier.java
deleted file mode 100644
index cbdad5e..0000000
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/PrivateKeySupplier.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.oauth.v2.functions;
-
-import static com.google.common.base.Charsets.UTF_8;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Throwables.propagate;
-import static org.jclouds.crypto.Pems.privateKeySpec;
-import static org.jclouds.oauth.v2.config.OAuthProperties.JWS_ALG;
-import static org.jclouds.util.Throwables2.getFirstThrowableOfType;
-
-import java.io.IOException;
-import java.security.KeyFactory;
-import java.security.PrivateKey;
-import java.security.spec.InvalidKeySpecException;
-
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-import org.jclouds.domain.Credentials;
-import org.jclouds.location.Provider;
-import org.jclouds.oauth.v2.JWSAlgorithms;
-import org.jclouds.rest.AuthorizationException;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Supplier;
-import com.google.common.cache.CacheBuilder;
-import com.google.common.cache.CacheLoader;
-import com.google.common.cache.LoadingCache;
-import com.google.common.io.ByteSource;
-import com.google.common.util.concurrent.UncheckedExecutionException;
-
-/**
- * Loads {@link PrivateKey} from a pem private key using the KeyFactory obtained vi {@link
- * JWSAlgorithms#keyFactory(String)}. The pem pk algorithm must match the KeyFactory algorithm.
- */
-@Singleton // due to cache
-public final class PrivateKeySupplier implements Supplier<PrivateKey> {
-
-   private final Supplier<Credentials> creds;
-   private final LoadingCache<Credentials, PrivateKey> keyCache;
-
-   @Inject PrivateKeySupplier(@Provider Supplier<Credentials> creds, PrivateKeyForCredentials loader) {
-      this.creds = creds;
-      // throw out the private key related to old credentials
-      this.keyCache = CacheBuilder.newBuilder().maximumSize(2).build(checkNotNull(loader, "loader"));
-   }
-
-   /**
-    * it is relatively expensive to extract a private key from a PEM. cache the relationship between current
-    * credentials
-    * so that the private key is only recalculated once.
-    */
-   @VisibleForTesting
-   static final class PrivateKeyForCredentials extends CacheLoader<Credentials, PrivateKey> {
-      private final String jwsAlg;
-
-      @Inject PrivateKeyForCredentials(@Named(JWS_ALG) String jwsAlg) {
-         this.jwsAlg = jwsAlg;
-      }
-
-      @Override public PrivateKey load(Credentials in) {
-         try {
-            String privateKeyInPemFormat = in.credential;
-            KeyFactory keyFactory = JWSAlgorithms.keyFactory(jwsAlg);
-            return keyFactory.generatePrivate(privateKeySpec(ByteSource.wrap(privateKeyInPemFormat.getBytes(UTF_8))));
-         } catch (IOException e) {
-            throw propagate(e);
-         } catch (InvalidKeySpecException e) {
-            throw new AuthorizationException("security exception loading credentials. " + e.getMessage(), e);
-            // catch IAE that is thrown when parsing the pk fails
-         } catch (IllegalArgumentException e) {
-            throw new AuthorizationException("cannot parse pk. " + e.getMessage(), e);
-         }
-      }
-   }
-
-   @Override public PrivateKey get() {
-      try {
-         // loader always throws UncheckedExecutionException so no point in using get()
-         return keyCache.getUnchecked(checkNotNull(creds.get(), "credential supplier returned null"));
-      } catch (UncheckedExecutionException e) {
-         AuthorizationException authorizationException = getFirstThrowableOfType(e, AuthorizationException.class);
-         if (authorizationException != null) {
-            throw authorizationException;
-         }
-         throw e;
-      }
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/SignOrProduceMacForToken.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/SignOrProduceMacForToken.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/SignOrProduceMacForToken.java
deleted file mode 100644
index fd827b1..0000000
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/functions/SignOrProduceMacForToken.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.oauth.v2.functions;
-
-import static com.google.common.base.Throwables.propagate;
-import static org.jclouds.oauth.v2.JWSAlgorithms.macOrSignature;
-import static org.jclouds.oauth.v2.config.OAuthProperties.JWS_ALG;
-
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
-import java.security.PrivateKey;
-import java.security.Signature;
-import java.security.SignatureException;
-
-import javax.crypto.Mac;
-import javax.inject.Inject;
-import javax.inject.Named;
-
-import org.jclouds.oauth.v2.config.OAuth;
-import org.jclouds.rest.AuthorizationException;
-
-import com.google.common.base.Function;
-import com.google.common.base.Supplier;
-
-/**
- * Function that signs/produces mac's for  OAuth tokens, provided a {@link Signature} or a {@link Mac} algorithm and
- * {@link PrivateKey}
- */
-public final class SignOrProduceMacForToken implements Supplier<Function<byte[], byte[]>> {
-
-   private final String macOrSignature;
-   private final Supplier<PrivateKey> credentials;
-
-   @Inject SignOrProduceMacForToken(@Named(JWS_ALG) String jwsAlg, @OAuth Supplier<PrivateKey> credentials) {
-      this.macOrSignature = macOrSignature(jwsAlg);
-      this.credentials = credentials;
-   }
-
-   @Override public Function<byte[], byte[]> get() {
-      try {
-         if (macOrSignature.startsWith("SHA")) {
-            return new SignatureGenerator(macOrSignature, credentials.get());
-         }
-         return new MessageAuthenticationCodeGenerator(macOrSignature, credentials.get());
-      } catch (NoSuchAlgorithmException e) {
-         throw new AssertionError("Invalid contents in JWSAlgorithms! " + e.getMessage());
-      } catch (InvalidKeyException e) {
-         throw new AuthorizationException("cannot parse pk. " + e.getMessage(), e);
-      }
-   }
-
-   private static class MessageAuthenticationCodeGenerator implements Function<byte[], byte[]> {
-
-      private final Mac mac;
-
-      private MessageAuthenticationCodeGenerator(String macAlgorithm, PrivateKey privateKey) throws
-              NoSuchAlgorithmException, InvalidKeyException {
-         this.mac = Mac.getInstance(macAlgorithm);
-         this.mac.init(privateKey);
-      }
-
-      @Override public byte[] apply(byte[] input) {
-         this.mac.update(input);
-         return this.mac.doFinal();
-      }
-   }
-
-   private static class SignatureGenerator implements Function<byte[], byte[]> {
-
-      private final Signature signature;
-
-      private SignatureGenerator(String signatureAlgorithm, PrivateKey privateKey) throws NoSuchAlgorithmException,
-              InvalidKeyException {
-         this.signature = Signature.getInstance(signatureAlgorithm);
-         this.signature.initSign(privateKey);
-      }
-
-      @Override public byte[] apply(byte[] input) {
-         try {
-            signature.update(input);
-            return signature.sign();
-         } catch (SignatureException e) {
-            throw propagate(e);
-         }
-      }
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/46a7351a/apis/oauth/src/main/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandler.java
----------------------------------------------------------------------
diff --git a/apis/oauth/src/main/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandler.java b/apis/oauth/src/main/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandler.java
deleted file mode 100644
index ddc88a8..0000000
--- a/apis/oauth/src/main/java/org/jclouds/oauth/v2/handlers/OAuthErrorHandler.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.oauth.v2.handlers;
-
-import static javax.ws.rs.core.Response.Status;
-import static org.jclouds.http.HttpUtils.closeClientButKeepContentStream;
-
-import org.jclouds.http.HttpCommand;
-import org.jclouds.http.HttpErrorHandler;
-import org.jclouds.http.HttpResponse;
-import org.jclouds.http.HttpResponseException;
-import org.jclouds.rest.AuthorizationException;
-import org.jclouds.rest.ResourceNotFoundException;
-
-public final class OAuthErrorHandler implements HttpErrorHandler {
-   @Override public void handleError(HttpCommand command, HttpResponse response) {
-      // it is important to always read fully and close streams
-      byte[] data = closeClientButKeepContentStream(response);
-      String message = data != null ? new String(data) : null;
-
-      Exception exception = message != null ? new HttpResponseException(command, response, message)
-              : new HttpResponseException(command, response);
-      message = message != null ? message : String.format("%s -> %s", command.getCurrentRequest().getRequestLine(),
-              response.getStatusLine());
-      Status status = Status.fromStatusCode(response.getStatusCode());
-      switch (status) {
-         case BAD_REQUEST:
-            break;
-         case UNAUTHORIZED:
-         case FORBIDDEN:
-            exception = new AuthorizationException(message, exception);
-            break;
-         case NOT_FOUND:
-            if (!command.getCurrentRequest().getMethod().equals("DELETE")) {
-               exception = new ResourceNotFoundException(message, exception);
-            }
-            break;
-         case CONFLICT:
-            exception = new IllegalStateException(message, exception);
-            break;
-      }
-      command.setException(exception);
-   }
-}